Python-checkins
Threads by month
- ----- 2025 -----
- February
- January
- ----- 2024 -----
- December
- November
- October
- September
- August
- July
- June
- May
- April
- March
- February
- January
- ----- 2023 -----
- December
- November
- October
- September
- August
- July
- June
- May
- April
- March
- February
- January
- ----- 2022 -----
- December
- November
- October
- September
- August
- July
- June
- May
- April
- March
- February
- January
- ----- 2021 -----
- December
- November
- October
- September
- August
- July
- June
- May
- April
- March
- February
- January
- ----- 2020 -----
- December
- November
- October
- September
- August
- July
- June
- May
- April
- March
- February
- January
- ----- 2019 -----
- December
- November
- October
- September
- August
- July
- June
- May
- April
- March
- February
- January
- ----- 2018 -----
- December
- November
- October
- September
- August
- July
- June
- May
- April
- March
- February
- January
- ----- 2017 -----
- December
- November
- October
- September
- August
- July
- June
- May
- April
- March
- February
- January
- ----- 2016 -----
- December
- November
- October
- September
- August
- July
- June
- May
- April
- March
- February
- January
- ----- 2015 -----
- December
- November
- October
- September
- August
- July
- June
- May
- April
- March
- February
- January
- ----- 2014 -----
- December
- November
- October
- September
- August
- July
- June
- May
- April
- March
- February
- January
- ----- 2013 -----
- December
- November
- October
- September
- August
- July
- June
- May
- April
- March
- February
- January
- ----- 2012 -----
- December
- November
- October
- September
- August
- July
- June
- May
- April
- March
- February
- January
- ----- 2011 -----
- December
- November
- October
- September
- August
- July
- June
- May
- April
- March
- February
- January
- ----- 2010 -----
- December
- November
- October
- September
- August
- July
- June
- May
- April
- March
- February
- January
- ----- 2009 -----
- December
- November
- October
- September
- August
- July
- June
- May
- April
- March
- February
- January
- ----- 2008 -----
- December
- November
- October
- September
- August
- July
- June
- May
- April
- March
- February
- January
- ----- 2007 -----
- December
- November
- October
- September
- August
- July
- June
- May
- April
- March
- February
- January
- ----- 2006 -----
- December
- November
- October
- September
- August
- July
- June
- May
- April
- March
- February
- January
- ----- 2005 -----
- December
- November
- October
- September
- August
- July
- June
- May
- April
- March
- February
- January
- ----- 2004 -----
- December
- November
- October
- September
- August
- July
- June
- May
- April
- March
- February
- January
- ----- 2003 -----
- December
- November
- October
- September
- August
January 2025
- 1 participants
- 705 discussions
gh-128910: Remove `_PyTrash_begin` and `_PyTrash_end` C-API functions (#128919)
by sobolevn Jan. 16, 2025
by sobolevn Jan. 16, 2025
Jan. 16, 2025
https://github.com/python/cpython/commit/f48702dade921beed3e227d2a5ac82a9ae…
commit: f48702dade921beed3e227d2a5ac82a9ae2533d0
branch: main
author: sobolevn <mail(a)sobolevn.me>
committer: sobolevn <mail(a)sobolevn.me>
date: 2025-01-16T15:41:40Z
summary:
gh-128910: Remove `_PyTrash_begin` and `_PyTrash_end` C-API functions (#128919)
files:
A Misc/NEWS.d/next/Core_and_Builtins/2025-01-16-18-16-18.gh-issue-128910.9pqfab.rst
M Include/cpython/object.h
diff --git a/Include/cpython/object.h b/Include/cpython/object.h
index c8c6bc97fa32ee..ba31e2464abf84 100644
--- a/Include/cpython/object.h
+++ b/Include/cpython/object.h
@@ -475,9 +475,6 @@ partially-deallocated object. To check this, the tp_dealloc function must be
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);
diff --git a/Misc/NEWS.d/next/Core_and_Builtins/2025-01-16-18-16-18.gh-issue-128910.9pqfab.rst b/Misc/NEWS.d/next/Core_and_Builtins/2025-01-16-18-16-18.gh-issue-128910.9pqfab.rst
new file mode 100644
index 00000000000000..e095ba9ebf6be4
--- /dev/null
+++ b/Misc/NEWS.d/next/Core_and_Builtins/2025-01-16-18-16-18.gh-issue-128910.9pqfab.rst
@@ -0,0 +1,2 @@
+Undocumented and unused private C-API functions ``_PyTrash_begin`` and
+``_PyTrash_end`` are removed.
1
0
Jan. 16, 2025
https://github.com/python/cpython/commit/3893a92d956363fa2443bc5e47d4bae3de…
commit: 3893a92d956363fa2443bc5e47d4bae3deddacef
branch: main
author: Irit Katriel <1055913+iritkatriel(a)users.noreply.github.com>
committer: iritkatriel <1055913+iritkatriel(a)users.noreply.github.com>
date: 2025-01-16T15:22:13Z
summary:
gh-100239: specialize long tail of binary operations (#128722)
files:
A Misc/NEWS.d/next/Core_and_Builtins/2025-01-10-23-54-16.gh-issue-100239.ijOOUs.rst
M Include/internal/pycore_code.h
M Include/internal/pycore_magic_number.h
M Include/internal/pycore_opcode_metadata.h
M Include/internal/pycore_uop_ids.h
M Include/internal/pycore_uop_metadata.h
M Include/opcode_ids.h
M Lib/_opcode_metadata.py
M Lib/opcode.py
M Lib/test/test_code.py
M Lib/test/test_dis.py
M Lib/test/test_monitoring.py
M Lib/test/test_opcache.py
M Python/bytecodes.c
M Python/executor_cases.c.h
M Python/generated_cases.c.h
M Python/opcode_targets.h
M Python/optimizer_cases.c.h
M Python/specialize.c
M Tools/c-analyzer/cpython/ignored.tsv
M Tools/cases_generator/parsing.py
diff --git a/Include/internal/pycore_code.h b/Include/internal/pycore_code.h
index d97fe81a2fc54a..01d41446fdb0cf 100644
--- a/Include/internal/pycore_code.h
+++ b/Include/internal/pycore_code.h
@@ -100,6 +100,7 @@ typedef struct {
typedef struct {
_Py_BackoffCounter counter;
+ uint16_t external_cache[4];
} _PyBinaryOpCache;
#define INLINE_CACHE_ENTRIES_BINARY_OP CACHE_ENTRIES(_PyBinaryOpCache)
@@ -438,7 +439,7 @@ write_u64(uint16_t *p, uint64_t val)
}
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,16 @@ adaptive_counter_backoff(_Py_BackoffCounter counter) {
return restart_backoff_counter(counter);
}
+/* Specialization Extensions */
+
+/* callbacks for an external specialization */
+typedef int (*binaryopguardfunc)(PyObject *lhs, PyObject *rhs);
+typedef PyObject *(*binaryopactionfunc)(PyObject *lhs, PyObject *rhs);
+
+typedef struct {
+ binaryopguardfunc guard;
+ binaryopactionfunc action;
+} _PyBinaryOpSpecializationDescr;
/* Comparison bit masks. */
diff --git a/Include/internal/pycore_magic_number.h b/Include/internal/pycore_magic_number.h
index 8b3d6285c1e4e7..1dd155abf3babf 100644
--- a/Include/internal/pycore_magic_number.h
+++ b/Include/internal/pycore_magic_number.h
@@ -266,6 +266,7 @@ Known values:
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.15 will start with 3650
@@ -278,7 +279,7 @@ PC/launcher.c must also be updated.
*/
-#define PYC_MAGIC_NUMBER 3613
+#define PYC_MAGIC_NUMBER 3614
/* 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_opcode_metadata.h b/Include/internal/pycore_opcode_metadata.h
index 0c0a6145bdbb27..f7c23ad634d6be 100644
--- a/Include/internal/pycore_opcode_metadata.h
+++ b/Include/internal/pycore_opcode_metadata.h
@@ -43,6 +43,8 @@ int _PyOpcode_num_popped(int opcode, int oparg) {
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:
@@ -512,6 +514,8 @@ int _PyOpcode_num_pushed(int opcode, int oparg) {
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:
@@ -989,6 +993,10 @@ int _PyOpcode_max_stack_effect(int opcode, int oparg, int *effect) {
*effect = 0;
return 0;
}
+ case BINARY_OP_EXTEND: {
+ *effect = 0;
+ return 0;
+ }
case BINARY_OP_INPLACE_ADD_UNICODE: {
*effect = 0;
return 0;
@@ -1919,11 +1927,13 @@ enum InstructionFormat {
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) \
@@ -1981,15 +1991,16 @@ struct opcode_metadata {
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_EXIT_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_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 },
@@ -2227,6 +2238,7 @@ _PyOpcode_macro_expansion[256] = {
[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 } } },
@@ -2411,6 +2423,7 @@ const char *_PyOpcode_OpName[266] = {
[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",
@@ -2661,7 +2674,7 @@ const uint8_t _PyOpcode_Caches[256] = {
[FOR_ITER] = 1,
[CALL] = 3,
[CALL_KW] = 3,
- [BINARY_OP] = 1,
+ [BINARY_OP] = 5,
};
#endif
@@ -2672,6 +2685,7 @@ const uint8_t _PyOpcode_Deopt[256] = {
[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,
@@ -2923,7 +2937,6 @@ const uint8_t _PyOpcode_Deopt[256] = {
case 146: \
case 147: \
case 148: \
- case 229: \
case 230: \
case 231: \
case 232: \
diff --git a/Include/internal/pycore_uop_ids.h b/Include/internal/pycore_uop_ids.h
index 3841363b411eed..f95defbc364aed 100644
--- a/Include/internal/pycore_uop_ids.h
+++ b/Include/internal/pycore_uop_ids.h
@@ -15,16 +15,17 @@ extern "C" {
#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_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_SUBTRACT_FLOAT 310
+#define _BINARY_OP_SUBTRACT_INT 311
+#define _BINARY_SLICE 312
+#define _BINARY_SUBSCR 313
+#define _BINARY_SUBSCR_CHECK_FUNC 314
#define _BINARY_SUBSCR_DICT BINARY_SUBSCR_DICT
-#define _BINARY_SUBSCR_INIT_CALL 314
+#define _BINARY_SUBSCR_INIT_CALL 315
#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
@@ -34,122 +35,123 @@ extern "C" {
#define _BUILD_SLICE BUILD_SLICE
#define _BUILD_STRING BUILD_STRING
#define _BUILD_TUPLE BUILD_TUPLE
-#define _CALL_BUILTIN_CLASS 315
-#define _CALL_BUILTIN_FAST 316
-#define _CALL_BUILTIN_FAST_WITH_KEYWORDS 317
-#define _CALL_BUILTIN_O 318
+#define _CALL_BUILTIN_CLASS 316
+#define _CALL_BUILTIN_FAST 317
+#define _CALL_BUILTIN_FAST_WITH_KEYWORDS 318
+#define _CALL_BUILTIN_O 319
#define _CALL_INTRINSIC_1 CALL_INTRINSIC_1
#define _CALL_INTRINSIC_2 CALL_INTRINSIC_2
#define _CALL_ISINSTANCE CALL_ISINSTANCE
-#define _CALL_KW_NON_PY 319
+#define _CALL_KW_NON_PY 320
#define _CALL_LEN CALL_LEN
#define _CALL_LIST_APPEND CALL_LIST_APPEND
-#define _CALL_METHOD_DESCRIPTOR_FAST 320
-#define _CALL_METHOD_DESCRIPTOR_FAST_WITH_KEYWORDS 321
-#define _CALL_METHOD_DESCRIPTOR_NOARGS 322
-#define _CALL_METHOD_DESCRIPTOR_O 323
-#define _CALL_NON_PY_GENERAL 324
-#define _CALL_STR_1 325
-#define _CALL_TUPLE_1 326
+#define _CALL_METHOD_DESCRIPTOR_FAST 321
+#define _CALL_METHOD_DESCRIPTOR_FAST_WITH_KEYWORDS 322
+#define _CALL_METHOD_DESCRIPTOR_NOARGS 323
+#define _CALL_METHOD_DESCRIPTOR_O 324
+#define _CALL_NON_PY_GENERAL 325
+#define _CALL_STR_1 326
+#define _CALL_TUPLE_1 327
#define _CALL_TYPE_1 CALL_TYPE_1
-#define _CHECK_AND_ALLOCATE_OBJECT 327
-#define _CHECK_ATTR_CLASS 328
-#define _CHECK_ATTR_METHOD_LAZY_DICT 329
-#define _CHECK_ATTR_MODULE_PUSH_KEYS 330
-#define _CHECK_ATTR_WITH_HINT 331
-#define _CHECK_CALL_BOUND_METHOD_EXACT_ARGS 332
+#define _CHECK_AND_ALLOCATE_OBJECT 328
+#define _CHECK_ATTR_CLASS 329
+#define _CHECK_ATTR_METHOD_LAZY_DICT 330
+#define _CHECK_ATTR_MODULE_PUSH_KEYS 331
+#define _CHECK_ATTR_WITH_HINT 332
+#define _CHECK_CALL_BOUND_METHOD_EXACT_ARGS 333
#define _CHECK_EG_MATCH CHECK_EG_MATCH
#define _CHECK_EXC_MATCH CHECK_EXC_MATCH
-#define _CHECK_FUNCTION 333
-#define _CHECK_FUNCTION_EXACT_ARGS 334
-#define _CHECK_FUNCTION_VERSION 335
-#define _CHECK_FUNCTION_VERSION_INLINE 336
-#define _CHECK_FUNCTION_VERSION_KW 337
-#define _CHECK_IS_NOT_PY_CALLABLE 338
-#define _CHECK_IS_NOT_PY_CALLABLE_KW 339
-#define _CHECK_MANAGED_OBJECT_HAS_VALUES 340
-#define _CHECK_METHOD_VERSION 341
-#define _CHECK_METHOD_VERSION_KW 342
-#define _CHECK_PEP_523 343
-#define _CHECK_PERIODIC 344
-#define _CHECK_PERIODIC_IF_NOT_YIELD_FROM 345
-#define _CHECK_STACK_SPACE 346
-#define _CHECK_STACK_SPACE_OPERAND 347
-#define _CHECK_VALIDITY 348
-#define _CHECK_VALIDITY_AND_SET_IP 349
-#define _COMPARE_OP 350
-#define _COMPARE_OP_FLOAT 351
-#define _COMPARE_OP_INT 352
-#define _COMPARE_OP_STR 353
-#define _CONTAINS_OP 354
+#define _CHECK_FUNCTION 334
+#define _CHECK_FUNCTION_EXACT_ARGS 335
+#define _CHECK_FUNCTION_VERSION 336
+#define _CHECK_FUNCTION_VERSION_INLINE 337
+#define _CHECK_FUNCTION_VERSION_KW 338
+#define _CHECK_IS_NOT_PY_CALLABLE 339
+#define _CHECK_IS_NOT_PY_CALLABLE_KW 340
+#define _CHECK_MANAGED_OBJECT_HAS_VALUES 341
+#define _CHECK_METHOD_VERSION 342
+#define _CHECK_METHOD_VERSION_KW 343
+#define _CHECK_PEP_523 344
+#define _CHECK_PERIODIC 345
+#define _CHECK_PERIODIC_IF_NOT_YIELD_FROM 346
+#define _CHECK_STACK_SPACE 347
+#define _CHECK_STACK_SPACE_OPERAND 348
+#define _CHECK_VALIDITY 349
+#define _CHECK_VALIDITY_AND_SET_IP 350
+#define _COMPARE_OP 351
+#define _COMPARE_OP_FLOAT 352
+#define _COMPARE_OP_INT 353
+#define _COMPARE_OP_STR 354
+#define _CONTAINS_OP 355
#define _CONTAINS_OP_DICT CONTAINS_OP_DICT
#define _CONTAINS_OP_SET CONTAINS_OP_SET
#define _CONVERT_VALUE CONVERT_VALUE
#define _COPY COPY
#define _COPY_FREE_VARS COPY_FREE_VARS
-#define _CREATE_INIT_FRAME 355
+#define _CREATE_INIT_FRAME 356
#define _DELETE_ATTR DELETE_ATTR
#define _DELETE_DEREF DELETE_DEREF
#define _DELETE_FAST DELETE_FAST
#define _DELETE_GLOBAL DELETE_GLOBAL
#define _DELETE_NAME DELETE_NAME
#define _DELETE_SUBSCR DELETE_SUBSCR
-#define _DEOPT 356
+#define _DEOPT 357
#define _DICT_MERGE DICT_MERGE
#define _DICT_UPDATE DICT_UPDATE
-#define _DO_CALL 357
-#define _DO_CALL_FUNCTION_EX 358
-#define _DO_CALL_KW 359
-#define _DYNAMIC_EXIT 360
+#define _DO_CALL 358
+#define _DO_CALL_FUNCTION_EX 359
+#define _DO_CALL_KW 360
+#define _DYNAMIC_EXIT 361
#define _END_FOR END_FOR
#define _END_SEND END_SEND
-#define _ERROR_POP_N 361
+#define _ERROR_POP_N 362
#define _EXIT_INIT_CHECK EXIT_INIT_CHECK
-#define _EXPAND_METHOD 362
-#define _EXPAND_METHOD_KW 363
-#define _FATAL_ERROR 364
+#define _EXPAND_METHOD 363
+#define _EXPAND_METHOD_KW 364
+#define _FATAL_ERROR 365
#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 366
+#define _FOR_ITER_GEN_FRAME 367
+#define _FOR_ITER_TIER_TWO 368
#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_BOTH_FLOAT 368
-#define _GUARD_BOTH_INT 369
-#define _GUARD_BOTH_UNICODE 370
-#define _GUARD_BUILTINS_VERSION_PUSH_KEYS 371
-#define _GUARD_DORV_NO_DICT 372
-#define _GUARD_DORV_VALUES_INST_ATTR_FROM_DICT 373
-#define _GUARD_GLOBALS_VERSION 374
-#define _GUARD_GLOBALS_VERSION_PUSH_KEYS 375
-#define _GUARD_IS_FALSE_POP 376
-#define _GUARD_IS_NONE_POP 377
-#define _GUARD_IS_NOT_NONE_POP 378
-#define _GUARD_IS_TRUE_POP 379
-#define _GUARD_KEYS_VERSION 380
-#define _GUARD_NOS_FLOAT 381
-#define _GUARD_NOS_INT 382
-#define _GUARD_NOT_EXHAUSTED_LIST 383
-#define _GUARD_NOT_EXHAUSTED_RANGE 384
-#define _GUARD_NOT_EXHAUSTED_TUPLE 385
-#define _GUARD_TOS_FLOAT 386
-#define _GUARD_TOS_INT 387
-#define _GUARD_TYPE_VERSION 388
-#define _GUARD_TYPE_VERSION_AND_LOCK 389
+#define _GUARD_BINARY_OP_EXTEND 369
+#define _GUARD_BOTH_FLOAT 370
+#define _GUARD_BOTH_INT 371
+#define _GUARD_BOTH_UNICODE 372
+#define _GUARD_BUILTINS_VERSION_PUSH_KEYS 373
+#define _GUARD_DORV_NO_DICT 374
+#define _GUARD_DORV_VALUES_INST_ATTR_FROM_DICT 375
+#define _GUARD_GLOBALS_VERSION 376
+#define _GUARD_GLOBALS_VERSION_PUSH_KEYS 377
+#define _GUARD_IS_FALSE_POP 378
+#define _GUARD_IS_NONE_POP 379
+#define _GUARD_IS_NOT_NONE_POP 380
+#define _GUARD_IS_TRUE_POP 381
+#define _GUARD_KEYS_VERSION 382
+#define _GUARD_NOS_FLOAT 383
+#define _GUARD_NOS_INT 384
+#define _GUARD_NOT_EXHAUSTED_LIST 385
+#define _GUARD_NOT_EXHAUSTED_RANGE 386
+#define _GUARD_NOT_EXHAUSTED_TUPLE 387
+#define _GUARD_TOS_FLOAT 388
+#define _GUARD_TOS_INT 389
+#define _GUARD_TYPE_VERSION 390
+#define _GUARD_TYPE_VERSION_AND_LOCK 391
#define _IMPORT_FROM IMPORT_FROM
#define _IMPORT_NAME IMPORT_NAME
-#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 _INIT_CALL_BOUND_METHOD_EXACT_ARGS 392
+#define _INIT_CALL_PY_EXACT_ARGS 393
+#define _INIT_CALL_PY_EXACT_ARGS_0 394
+#define _INIT_CALL_PY_EXACT_ARGS_1 395
+#define _INIT_CALL_PY_EXACT_ARGS_2 396
+#define _INIT_CALL_PY_EXACT_ARGS_3 397
+#define _INIT_CALL_PY_EXACT_ARGS_4 398
#define _INSTRUMENTED_CALL_FUNCTION_EX INSTRUMENTED_CALL_FUNCTION_EX
#define _INSTRUMENTED_CALL_KW INSTRUMENTED_CALL_KW
#define _INSTRUMENTED_FOR_ITER INSTRUMENTED_FOR_ITER
@@ -162,144 +164,144 @@ extern "C" {
#define _INSTRUMENTED_POP_JUMP_IF_NONE INSTRUMENTED_POP_JUMP_IF_NONE
#define _INSTRUMENTED_POP_JUMP_IF_NOT_NONE INSTRUMENTED_POP_JUMP_IF_NOT_NONE
#define _INSTRUMENTED_POP_JUMP_IF_TRUE INSTRUMENTED_POP_JUMP_IF_TRUE
-#define _INTERNAL_INCREMENT_OPT_COUNTER 397
-#define _IS_NONE 398
+#define _INTERNAL_INCREMENT_OPT_COUNTER 399
+#define _IS_NONE 400
#define _IS_OP IS_OP
-#define _ITER_CHECK_LIST 399
-#define _ITER_CHECK_RANGE 400
-#define _ITER_CHECK_TUPLE 401
-#define _ITER_JUMP_LIST 402
-#define _ITER_JUMP_RANGE 403
-#define _ITER_JUMP_TUPLE 404
-#define _ITER_NEXT_LIST 405
-#define _ITER_NEXT_RANGE 406
-#define _ITER_NEXT_TUPLE 407
-#define _JUMP_TO_TOP 408
+#define _ITER_CHECK_LIST 401
+#define _ITER_CHECK_RANGE 402
+#define _ITER_CHECK_TUPLE 403
+#define _ITER_JUMP_LIST 404
+#define _ITER_JUMP_RANGE 405
+#define _ITER_JUMP_TUPLE 406
+#define _ITER_NEXT_LIST 407
+#define _ITER_NEXT_RANGE 408
+#define _ITER_NEXT_TUPLE 409
+#define _JUMP_TO_TOP 410
#define _LIST_APPEND LIST_APPEND
#define _LIST_EXTEND LIST_EXTEND
-#define _LOAD_ATTR 409
-#define _LOAD_ATTR_CLASS 410
-#define _LOAD_ATTR_CLASS_0 411
-#define _LOAD_ATTR_CLASS_1 412
+#define _LOAD_ATTR 411
+#define _LOAD_ATTR_CLASS 412
+#define _LOAD_ATTR_CLASS_0 413
+#define _LOAD_ATTR_CLASS_1 414
#define _LOAD_ATTR_GETATTRIBUTE_OVERRIDDEN LOAD_ATTR_GETATTRIBUTE_OVERRIDDEN
-#define _LOAD_ATTR_INSTANCE_VALUE 413
-#define _LOAD_ATTR_INSTANCE_VALUE_0 414
-#define _LOAD_ATTR_INSTANCE_VALUE_1 415
-#define _LOAD_ATTR_METHOD_LAZY_DICT 416
-#define _LOAD_ATTR_METHOD_NO_DICT 417
-#define _LOAD_ATTR_METHOD_WITH_VALUES 418
-#define _LOAD_ATTR_MODULE 419
-#define _LOAD_ATTR_MODULE_FROM_KEYS 420
-#define _LOAD_ATTR_NONDESCRIPTOR_NO_DICT 421
-#define _LOAD_ATTR_NONDESCRIPTOR_WITH_VALUES 422
-#define _LOAD_ATTR_PROPERTY_FRAME 423
-#define _LOAD_ATTR_SLOT 424
-#define _LOAD_ATTR_SLOT_0 425
-#define _LOAD_ATTR_SLOT_1 426
-#define _LOAD_ATTR_WITH_HINT 427
+#define _LOAD_ATTR_INSTANCE_VALUE 415
+#define _LOAD_ATTR_INSTANCE_VALUE_0 416
+#define _LOAD_ATTR_INSTANCE_VALUE_1 417
+#define _LOAD_ATTR_METHOD_LAZY_DICT 418
+#define _LOAD_ATTR_METHOD_NO_DICT 419
+#define _LOAD_ATTR_METHOD_WITH_VALUES 420
+#define _LOAD_ATTR_MODULE 421
+#define _LOAD_ATTR_MODULE_FROM_KEYS 422
+#define _LOAD_ATTR_NONDESCRIPTOR_NO_DICT 423
+#define _LOAD_ATTR_NONDESCRIPTOR_WITH_VALUES 424
+#define _LOAD_ATTR_PROPERTY_FRAME 425
+#define _LOAD_ATTR_SLOT 426
+#define _LOAD_ATTR_SLOT_0 427
+#define _LOAD_ATTR_SLOT_1 428
+#define _LOAD_ATTR_WITH_HINT 429
#define _LOAD_BUILD_CLASS LOAD_BUILD_CLASS
-#define _LOAD_BYTECODE 428
+#define _LOAD_BYTECODE 430
#define _LOAD_COMMON_CONSTANT LOAD_COMMON_CONSTANT
#define _LOAD_CONST LOAD_CONST
#define _LOAD_CONST_IMMORTAL LOAD_CONST_IMMORTAL
-#define _LOAD_CONST_INLINE 429
-#define _LOAD_CONST_INLINE_BORROW 430
-#define _LOAD_CONST_INLINE_BORROW_WITH_NULL 431
-#define _LOAD_CONST_INLINE_WITH_NULL 432
+#define _LOAD_CONST_INLINE 431
+#define _LOAD_CONST_INLINE_BORROW 432
+#define _LOAD_CONST_INLINE_BORROW_WITH_NULL 433
+#define _LOAD_CONST_INLINE_WITH_NULL 434
#define _LOAD_CONST_MORTAL LOAD_CONST_MORTAL
#define _LOAD_DEREF LOAD_DEREF
-#define _LOAD_FAST 433
-#define _LOAD_FAST_0 434
-#define _LOAD_FAST_1 435
-#define _LOAD_FAST_2 436
-#define _LOAD_FAST_3 437
-#define _LOAD_FAST_4 438
-#define _LOAD_FAST_5 439
-#define _LOAD_FAST_6 440
-#define _LOAD_FAST_7 441
+#define _LOAD_FAST 435
+#define _LOAD_FAST_0 436
+#define _LOAD_FAST_1 437
+#define _LOAD_FAST_2 438
+#define _LOAD_FAST_3 439
+#define _LOAD_FAST_4 440
+#define _LOAD_FAST_5 441
+#define _LOAD_FAST_6 442
+#define _LOAD_FAST_7 443
#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 442
-#define _LOAD_GLOBAL_BUILTINS 443
-#define _LOAD_GLOBAL_BUILTINS_FROM_KEYS 444
-#define _LOAD_GLOBAL_MODULE 445
-#define _LOAD_GLOBAL_MODULE_FROM_KEYS 446
+#define _LOAD_GLOBAL 444
+#define _LOAD_GLOBAL_BUILTINS 445
+#define _LOAD_GLOBAL_BUILTINS_FROM_KEYS 446
+#define _LOAD_GLOBAL_MODULE 447
+#define _LOAD_GLOBAL_MODULE_FROM_KEYS 448
#define _LOAD_LOCALS LOAD_LOCALS
#define _LOAD_NAME LOAD_NAME
-#define _LOAD_SMALL_INT 447
-#define _LOAD_SMALL_INT_0 448
-#define _LOAD_SMALL_INT_1 449
-#define _LOAD_SMALL_INT_2 450
-#define _LOAD_SMALL_INT_3 451
+#define _LOAD_SMALL_INT 449
+#define _LOAD_SMALL_INT_0 450
+#define _LOAD_SMALL_INT_1 451
+#define _LOAD_SMALL_INT_2 452
+#define _LOAD_SMALL_INT_3 453
#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 452
+#define _MAKE_CALLARGS_A_TUPLE 454
#define _MAKE_CELL MAKE_CELL
#define _MAKE_FUNCTION MAKE_FUNCTION
-#define _MAKE_WARM 453
+#define _MAKE_WARM 455
#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 454
-#define _MAYBE_EXPAND_METHOD_KW 455
-#define _MONITOR_CALL 456
-#define _MONITOR_JUMP_BACKWARD 457
-#define _MONITOR_RESUME 458
+#define _MAYBE_EXPAND_METHOD 456
+#define _MAYBE_EXPAND_METHOD_KW 457
+#define _MONITOR_CALL 458
+#define _MONITOR_JUMP_BACKWARD 459
+#define _MONITOR_RESUME 460
#define _NOP NOP
#define _POP_EXCEPT POP_EXCEPT
-#define _POP_JUMP_IF_FALSE 459
-#define _POP_JUMP_IF_TRUE 460
+#define _POP_JUMP_IF_FALSE 461
+#define _POP_JUMP_IF_TRUE 462
#define _POP_TOP POP_TOP
-#define _POP_TOP_LOAD_CONST_INLINE_BORROW 461
+#define _POP_TOP_LOAD_CONST_INLINE_BORROW 463
#define _PUSH_EXC_INFO PUSH_EXC_INFO
-#define _PUSH_FRAME 462
+#define _PUSH_FRAME 464
#define _PUSH_NULL PUSH_NULL
-#define _PY_FRAME_GENERAL 463
-#define _PY_FRAME_KW 464
-#define _QUICKEN_RESUME 465
-#define _REPLACE_WITH_TRUE 466
+#define _PY_FRAME_GENERAL 465
+#define _PY_FRAME_KW 466
+#define _QUICKEN_RESUME 467
+#define _REPLACE_WITH_TRUE 468
#define _RESUME_CHECK RESUME_CHECK
#define _RETURN_GENERATOR RETURN_GENERATOR
#define _RETURN_VALUE RETURN_VALUE
-#define _SAVE_RETURN_OFFSET 467
-#define _SEND 468
-#define _SEND_GEN_FRAME 469
+#define _SAVE_RETURN_OFFSET 469
+#define _SEND 470
+#define _SEND_GEN_FRAME 471
#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 470
-#define _STORE_ATTR 471
-#define _STORE_ATTR_INSTANCE_VALUE 472
-#define _STORE_ATTR_SLOT 473
-#define _STORE_ATTR_WITH_HINT 474
+#define _START_EXECUTOR 472
+#define _STORE_ATTR 473
+#define _STORE_ATTR_INSTANCE_VALUE 474
+#define _STORE_ATTR_SLOT 475
+#define _STORE_ATTR_WITH_HINT 476
#define _STORE_DEREF STORE_DEREF
-#define _STORE_FAST 475
-#define _STORE_FAST_0 476
-#define _STORE_FAST_1 477
-#define _STORE_FAST_2 478
-#define _STORE_FAST_3 479
-#define _STORE_FAST_4 480
-#define _STORE_FAST_5 481
-#define _STORE_FAST_6 482
-#define _STORE_FAST_7 483
+#define _STORE_FAST 477
+#define _STORE_FAST_0 478
+#define _STORE_FAST_1 479
+#define _STORE_FAST_2 480
+#define _STORE_FAST_3 481
+#define _STORE_FAST_4 482
+#define _STORE_FAST_5 483
+#define _STORE_FAST_6 484
+#define _STORE_FAST_7 485
#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 484
-#define _STORE_SUBSCR 485
+#define _STORE_SLICE 486
+#define _STORE_SUBSCR 487
#define _STORE_SUBSCR_DICT STORE_SUBSCR_DICT
#define _STORE_SUBSCR_LIST_INT STORE_SUBSCR_LIST_INT
#define _SWAP SWAP
-#define _TIER2_RESUME_CHECK 486
-#define _TO_BOOL 487
+#define _TIER2_RESUME_CHECK 488
+#define _TO_BOOL 489
#define _TO_BOOL_BOOL TO_BOOL_BOOL
#define _TO_BOOL_INT TO_BOOL_INT
#define _TO_BOOL_LIST TO_BOOL_LIST
@@ -309,13 +311,13 @@ extern "C" {
#define _UNARY_NEGATIVE UNARY_NEGATIVE
#define _UNARY_NOT UNARY_NOT
#define _UNPACK_EX UNPACK_EX
-#define _UNPACK_SEQUENCE 488
+#define _UNPACK_SEQUENCE 490
#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 488
+#define MAX_UOP_ID 490
#ifdef __cplusplus
}
diff --git a/Include/internal/pycore_uop_metadata.h b/Include/internal/pycore_uop_metadata.h
index 5670fe26f72071..298e918b872c62 100644
--- a/Include/internal/pycore_uop_metadata.h
+++ b/Include/internal/pycore_uop_metadata.h
@@ -82,6 +82,8 @@ const uint16_t _PyUop_Flags[MAX_UOP_ID+1] = {
[_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,
+ [_GUARD_BINARY_OP_EXTEND] = HAS_EXIT_FLAG | HAS_ESCAPES_FLAG,
+ [_BINARY_OP_EXTEND] = HAS_ESCAPES_FLAG | HAS_PURE_FLAG,
[_BINARY_SUBSCR] = HAS_ERROR_FLAG | HAS_ESCAPES_FLAG,
[_BINARY_SLICE] = HAS_ERROR_FLAG | HAS_ESCAPES_FLAG,
[_STORE_SLICE] = HAS_ERROR_FLAG | HAS_ESCAPES_FLAG,
@@ -309,6 +311,7 @@ const char *const _PyOpcode_uop_name[MAX_UOP_ID+1] = {
[_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",
@@ -410,6 +413,7 @@ const char *const _PyOpcode_uop_name[MAX_UOP_ID+1] = {
[_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",
@@ -711,6 +715,10 @@ int _PyUop_num_popped(int opcode, int oparg)
return 2;
case _BINARY_OP_INPLACE_ADD_UNICODE:
return 2;
+ case _GUARD_BINARY_OP_EXTEND:
+ return 0;
+ case _BINARY_OP_EXTEND:
+ return 2;
case _BINARY_SUBSCR:
return 2;
case _BINARY_SLICE:
diff --git a/Include/opcode_ids.h b/Include/opcode_ids.h
index f2d8963a1813c5..06b207b347e504 100644
--- a/Include/opcode_ids.h
+++ b/Include/opcode_ids.h
@@ -132,82 +132,83 @@ extern "C" {
#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_CONST_MORTAL 208
-#define LOAD_GLOBAL_BUILTIN 209
-#define LOAD_GLOBAL_MODULE 210
-#define LOAD_SUPER_ATTR_ATTR 211
-#define LOAD_SUPER_ATTR_METHOD 212
-#define RESUME_CHECK 213
-#define SEND_GEN 214
-#define STORE_ATTR_INSTANCE_VALUE 215
-#define STORE_ATTR_SLOT 216
-#define STORE_ATTR_WITH_HINT 217
-#define STORE_SUBSCR_DICT 218
-#define STORE_SUBSCR_LIST_INT 219
-#define TO_BOOL_ALWAYS_TRUE 220
-#define TO_BOOL_BOOL 221
-#define TO_BOOL_INT 222
-#define TO_BOOL_LIST 223
-#define TO_BOOL_NONE 224
-#define TO_BOOL_STR 225
-#define UNPACK_SEQUENCE_LIST 226
-#define UNPACK_SEQUENCE_TUPLE 227
-#define UNPACK_SEQUENCE_TWO_TUPLE 228
+#define BINARY_OP_EXTEND 153
+#define BINARY_OP_MULTIPLY_FLOAT 154
+#define BINARY_OP_MULTIPLY_INT 155
+#define BINARY_OP_SUBTRACT_FLOAT 156
+#define BINARY_OP_SUBTRACT_INT 157
+#define BINARY_SUBSCR_DICT 158
+#define BINARY_SUBSCR_GETITEM 159
+#define BINARY_SUBSCR_LIST_INT 160
+#define BINARY_SUBSCR_STR_INT 161
+#define BINARY_SUBSCR_TUPLE_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 LOAD_ATTR_CLASS 195
+#define LOAD_ATTR_CLASS_WITH_METACLASS_CHECK 196
+#define LOAD_ATTR_GETATTRIBUTE_OVERRIDDEN 197
+#define LOAD_ATTR_INSTANCE_VALUE 198
+#define LOAD_ATTR_METHOD_LAZY_DICT 199
+#define LOAD_ATTR_METHOD_NO_DICT 200
+#define LOAD_ATTR_METHOD_WITH_VALUES 201
+#define LOAD_ATTR_MODULE 202
+#define LOAD_ATTR_NONDESCRIPTOR_NO_DICT 203
+#define LOAD_ATTR_NONDESCRIPTOR_WITH_VALUES 204
+#define LOAD_ATTR_PROPERTY 205
+#define LOAD_ATTR_SLOT 206
+#define LOAD_ATTR_WITH_HINT 207
+#define LOAD_CONST_IMMORTAL 208
+#define LOAD_CONST_MORTAL 209
+#define LOAD_GLOBAL_BUILTIN 210
+#define LOAD_GLOBAL_MODULE 211
+#define LOAD_SUPER_ATTR_ATTR 212
+#define LOAD_SUPER_ATTR_METHOD 213
+#define RESUME_CHECK 214
+#define SEND_GEN 215
+#define STORE_ATTR_INSTANCE_VALUE 216
+#define STORE_ATTR_SLOT 217
+#define STORE_ATTR_WITH_HINT 218
+#define STORE_SUBSCR_DICT 219
+#define STORE_SUBSCR_LIST_INT 220
+#define TO_BOOL_ALWAYS_TRUE 221
+#define TO_BOOL_BOOL 222
+#define TO_BOOL_INT 223
+#define TO_BOOL_LIST 224
+#define TO_BOOL_NONE 225
+#define TO_BOOL_STR 226
+#define UNPACK_SEQUENCE_LIST 227
+#define UNPACK_SEQUENCE_TUPLE 228
+#define UNPACK_SEQUENCE_TWO_TUPLE 229
#define INSTRUMENTED_END_FOR 235
#define INSTRUMENTED_POP_ITER 236
#define INSTRUMENTED_END_SEND 237
diff --git a/Lib/_opcode_metadata.py b/Lib/_opcode_metadata.py
index d93e8d8df8fe4b..7dd528ef74df33 100644
--- a/Lib/_opcode_metadata.py
+++ b/Lib/_opcode_metadata.py
@@ -26,6 +26,7 @@
"BINARY_OP_ADD_FLOAT",
"BINARY_OP_SUBTRACT_FLOAT",
"BINARY_OP_ADD_UNICODE",
+ "BINARY_OP_EXTEND",
"BINARY_OP_INPLACE_ADD_UNICODE",
],
"BINARY_SUBSCR": [
@@ -123,83 +124,84 @@
'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_CONST_MORTAL': 208,
- 'LOAD_GLOBAL_BUILTIN': 209,
- 'LOAD_GLOBAL_MODULE': 210,
- 'LOAD_SUPER_ATTR_ATTR': 211,
- 'LOAD_SUPER_ATTR_METHOD': 212,
- 'RESUME_CHECK': 213,
- 'SEND_GEN': 214,
- 'STORE_ATTR_INSTANCE_VALUE': 215,
- 'STORE_ATTR_SLOT': 216,
- 'STORE_ATTR_WITH_HINT': 217,
- 'STORE_SUBSCR_DICT': 218,
- 'STORE_SUBSCR_LIST_INT': 219,
- 'TO_BOOL_ALWAYS_TRUE': 220,
- 'TO_BOOL_BOOL': 221,
- 'TO_BOOL_INT': 222,
- 'TO_BOOL_LIST': 223,
- 'TO_BOOL_NONE': 224,
- 'TO_BOOL_STR': 225,
- 'UNPACK_SEQUENCE_LIST': 226,
- 'UNPACK_SEQUENCE_TUPLE': 227,
- 'UNPACK_SEQUENCE_TWO_TUPLE': 228,
+ 'BINARY_OP_MULTIPLY_FLOAT': 154,
+ 'BINARY_OP_MULTIPLY_INT': 155,
+ 'BINARY_OP_SUBTRACT_FLOAT': 156,
+ 'BINARY_OP_SUBTRACT_INT': 157,
+ 'BINARY_SUBSCR_DICT': 158,
+ 'BINARY_SUBSCR_GETITEM': 159,
+ 'BINARY_SUBSCR_LIST_INT': 160,
+ 'BINARY_SUBSCR_STR_INT': 161,
+ 'BINARY_SUBSCR_TUPLE_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,
+ 'LOAD_ATTR_CLASS': 195,
+ 'LOAD_ATTR_CLASS_WITH_METACLASS_CHECK': 196,
+ 'LOAD_ATTR_GETATTRIBUTE_OVERRIDDEN': 197,
+ 'LOAD_ATTR_INSTANCE_VALUE': 198,
+ 'LOAD_ATTR_METHOD_LAZY_DICT': 199,
+ 'LOAD_ATTR_METHOD_NO_DICT': 200,
+ 'LOAD_ATTR_METHOD_WITH_VALUES': 201,
+ 'LOAD_ATTR_MODULE': 202,
+ 'LOAD_ATTR_NONDESCRIPTOR_NO_DICT': 203,
+ 'LOAD_ATTR_NONDESCRIPTOR_WITH_VALUES': 204,
+ 'LOAD_ATTR_PROPERTY': 205,
+ 'LOAD_ATTR_SLOT': 206,
+ 'LOAD_ATTR_WITH_HINT': 207,
+ 'LOAD_CONST_IMMORTAL': 208,
+ 'LOAD_CONST_MORTAL': 209,
+ 'LOAD_GLOBAL_BUILTIN': 210,
+ 'LOAD_GLOBAL_MODULE': 211,
+ 'LOAD_SUPER_ATTR_ATTR': 212,
+ 'LOAD_SUPER_ATTR_METHOD': 213,
+ 'RESUME_CHECK': 214,
+ 'SEND_GEN': 215,
+ 'STORE_ATTR_INSTANCE_VALUE': 216,
+ 'STORE_ATTR_SLOT': 217,
+ 'STORE_ATTR_WITH_HINT': 218,
+ 'STORE_SUBSCR_DICT': 219,
+ 'STORE_SUBSCR_LIST_INT': 220,
+ 'TO_BOOL_ALWAYS_TRUE': 221,
+ 'TO_BOOL_BOOL': 222,
+ 'TO_BOOL_INT': 223,
+ 'TO_BOOL_LIST': 224,
+ 'TO_BOOL_NONE': 225,
+ 'TO_BOOL_STR': 226,
+ 'UNPACK_SEQUENCE_LIST': 227,
+ 'UNPACK_SEQUENCE_TUPLE': 228,
+ 'UNPACK_SEQUENCE_TWO_TUPLE': 229,
}
opmap = {
diff --git a/Lib/opcode.py b/Lib/opcode.py
index aba66153af1b2e..4ee0d64026bd0a 100644
--- a/Lib/opcode.py
+++ b/Lib/opcode.py
@@ -52,6 +52,7 @@
},
"BINARY_OP": {
"counter": 1,
+ "descr": 4,
},
"UNPACK_SEQUENCE": {
"counter": 1,
diff --git a/Lib/test/test_code.py b/Lib/test/test_code.py
index 7ffa4eb8639add..69c1ee0690d269 100644
--- a/Lib/test/test_code.py
+++ b/Lib/test/test_code.py
@@ -429,14 +429,14 @@ def test_invalid_bytecode(self):
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()
diff --git a/Lib/test/test_dis.py b/Lib/test/test_dis.py
index 8afe9653f19f6e..da57aad2f84fbd 100644
--- a/Lib/test/test_dis.py
+++ b/Lib/test/test_dis.py
@@ -438,7 +438,7 @@ def foo(a: int, b: str) -> str:
LOAD_SMALL_INT 1
BINARY_OP 13 (+=)
STORE_NAME 0 (x)
- JUMP_BACKWARD 8 (to L1)
+ JUMP_BACKWARD 12 (to L1)
"""
dis_traceback = """\
@@ -843,7 +843,7 @@ def foo(x):
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)
@@ -851,7 +851,7 @@ def foo(x):
YIELD_VALUE 0
RESUME 5
POP_TOP
- JUMP_BACKWARD 12 (to L2)
+ JUMP_BACKWARD 16 (to L2)
L3: END_FOR
POP_ITER
LOAD_CONST 0 (None)
@@ -1807,7 +1807,7 @@ def _prepare_test_cases():
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=85, 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=97, arg=36, argval=204, 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='POP_JUMP_IF_FALSE', opcode=97, 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=89, 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=83, arg=0, argval='i', argrepr='i', offset=144, start_offset=144, starts_line=False, line_number=12, label=None, positions=None, cache_info=None),
@@ -1815,93 +1815,93 @@ def _prepare_test_cases():
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=83, 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=91, 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')]),
- Instruction(opname='STORE_FAST', opcode=109, arg=0, argval='i', argrepr='i', offset=164, start_offset=164, starts_line=False, line_number=13, label=None, positions=None, cache_info=None),
- Instruction(opname='LOAD_FAST', opcode=83, arg=0, argval='i', argrepr='i', offset=166, start_offset=166, starts_line=True, line_number=14, label=None, positions=None, cache_info=None),
- Instruction(opname='LOAD_SMALL_INT', opcode=91, arg=6, argval=6, argrepr='', offset=168, start_offset=168, starts_line=False, line_number=14, label=None, positions=None, cache_info=None),
- Instruction(opname='COMPARE_OP', opcode=56, arg=148, argval='>', argrepr='bool(>)', offset=170, start_offset=170, starts_line=False, line_number=14, label=None, positions=None, cache_info=[('counter', 1, b'\x00\x00')]),
- Instruction(opname='POP_JUMP_IF_FALSE', opcode=97, arg=3, argval=184, argrepr='to L6', offset=174, start_offset=174, 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=178, start_offset=178, starts_line=False, line_number=14, label=None, positions=None, cache_info=None),
- Instruction(opname='JUMP_BACKWARD', opcode=74, arg=33, argval=118, argrepr='to L5', offset=180, start_offset=180, starts_line=True, line_number=15, label=None, positions=None, cache_info=[('counter', 1, b'\x00\x00')]),
- Instruction(opname='LOAD_FAST', opcode=83, arg=0, argval='i', argrepr='i', offset=184, start_offset=184, starts_line=True, line_number=16, label=6, positions=None, cache_info=None),
- Instruction(opname='LOAD_SMALL_INT', opcode=91, arg=4, argval=4, argrepr='', offset=186, start_offset=186, starts_line=False, line_number=16, label=None, positions=None, cache_info=None),
- Instruction(opname='COMPARE_OP', opcode=56, arg=18, argval='<', argrepr='bool(<)', offset=188, start_offset=188, starts_line=False, line_number=16, label=None, positions=None, cache_info=[('counter', 1, b'\x00\x00')]),
- Instruction(opname='POP_JUMP_IF_TRUE', opcode=100, arg=3, argval=202, argrepr='to L7', offset=192, start_offset=192, 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=196, start_offset=196, starts_line=False, line_number=16, label=None, positions=None, cache_info=None),
- Instruction(opname='JUMP_BACKWARD', opcode=74, arg=42, argval=118, argrepr='to L5', offset=198, start_offset=198, starts_line=False, line_number=16, label=None, positions=None, cache_info=[('counter', 1, b'\x00\x00')]),
- Instruction(opname='JUMP_FORWARD', opcode=76, arg=11, argval=226, argrepr='to L9', offset=202, start_offset=202, starts_line=True, line_number=17, label=7, positions=None, cache_info=None),
- Instruction(opname='LOAD_GLOBAL', opcode=89, arg=3, argval='print', argrepr='print + NULL', offset=204, start_offset=204, 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=81, arg=1, argval='Who let lolcatz into this test suite?', argrepr="'Who let lolcatz into this test suite?'", offset=214, start_offset=214, starts_line=False, line_number=19, label=None, positions=None, cache_info=None),
- Instruction(opname='CALL', opcode=51, arg=1, argval=1, argrepr='', offset=216, start_offset=216, 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=224, start_offset=224, starts_line=False, line_number=19, label=None, positions=None, cache_info=None),
- Instruction(opname='NOP', opcode=27, arg=None, argval=None, argrepr='', offset=226, start_offset=226, starts_line=True, line_number=20, label=9, positions=None, cache_info=None),
- Instruction(opname='LOAD_SMALL_INT', opcode=91, arg=1, argval=1, argrepr='', offset=228, start_offset=228, starts_line=True, line_number=21, label=None, positions=None, cache_info=None),
- Instruction(opname='LOAD_SMALL_INT', opcode=91, arg=0, argval=0, argrepr='', offset=230, start_offset=230, 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=232, start_offset=232, starts_line=False, line_number=21, label=None, positions=None, cache_info=[('counter', 1, b'\x00\x00')]),
- Instruction(opname='POP_TOP', opcode=31, arg=None, argval=None, argrepr='', offset=236, start_offset=236, starts_line=False, line_number=21, label=None, positions=None, cache_info=None),
- Instruction(opname='LOAD_FAST', opcode=83, arg=0, argval='i', argrepr='i', offset=238, start_offset=238, starts_line=True, line_number=25, label=None, positions=None, cache_info=None),
- Instruction(opname='COPY', opcode=59, arg=1, argval=1, argrepr='', offset=240, start_offset=240, starts_line=False, line_number=25, label=None, positions=None, cache_info=None),
- Instruction(opname='LOAD_SPECIAL', opcode=92, arg=1, argval=1, argrepr='__exit__', offset=242, start_offset=242, starts_line=False, line_number=25, label=None, positions=None, cache_info=None),
- Instruction(opname='SWAP', opcode=114, arg=2, argval=2, argrepr='', offset=244, start_offset=244, starts_line=False, line_number=25, label=None, positions=None, cache_info=None),
- Instruction(opname='SWAP', opcode=114, arg=3, argval=3, argrepr='', offset=246, start_offset=246, starts_line=False, line_number=25, label=None, positions=None, cache_info=None),
- Instruction(opname='LOAD_SPECIAL', opcode=92, arg=0, argval=0, argrepr='__enter__', offset=248, start_offset=248, starts_line=False, line_number=25, label=None, positions=None, cache_info=None),
- Instruction(opname='CALL', opcode=51, arg=0, argval=0, argrepr='', offset=250, start_offset=250, 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=109, arg=1, argval='dodgy', argrepr='dodgy', offset=258, start_offset=258, starts_line=False, line_number=25, label=None, positions=None, cache_info=None),
- Instruction(opname='LOAD_GLOBAL', opcode=89, arg=3, argval='print', argrepr='print + NULL', offset=260, start_offset=260, 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=81, arg=2, argval='Never reach this', argrepr="'Never reach this'", offset=270, start_offset=270, starts_line=False, line_number=26, label=None, positions=None, cache_info=None),
- Instruction(opname='CALL', opcode=51, arg=1, argval=1, argrepr='', offset=272, start_offset=272, 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=280, start_offset=280, starts_line=False, line_number=26, label=None, positions=None, cache_info=None),
- Instruction(opname='LOAD_CONST', opcode=81, arg=3, argval=None, argrepr='None', offset=282, start_offset=282, starts_line=True, line_number=25, label=None, positions=None, cache_info=None),
- Instruction(opname='LOAD_CONST', opcode=81, arg=3, argval=None, argrepr='None', offset=284, start_offset=284, starts_line=False, line_number=25, label=None, positions=None, cache_info=None),
- Instruction(opname='LOAD_CONST', opcode=81, arg=3, argval=None, argrepr='None', offset=286, start_offset=286, starts_line=False, line_number=25, label=None, positions=None, cache_info=None),
- Instruction(opname='CALL', opcode=51, arg=3, argval=3, argrepr='', offset=288, start_offset=288, 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=296, start_offset=296, starts_line=False, line_number=25, label=None, positions=None, cache_info=None),
- Instruction(opname='LOAD_GLOBAL', opcode=89, arg=3, argval='print', argrepr='print + NULL', offset=298, start_offset=298, 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=81, arg=5, argval="OK, now we're done", argrepr='"OK, now we\'re done"', offset=308, start_offset=308, starts_line=False, line_number=28, label=None, positions=None, cache_info=None),
- Instruction(opname='CALL', opcode=51, arg=1, argval=1, argrepr='', offset=310, start_offset=310, 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=318, start_offset=318, starts_line=False, line_number=28, label=None, positions=None, cache_info=None),
- Instruction(opname='LOAD_CONST', opcode=81, arg=3, argval=None, argrepr='None', offset=320, start_offset=320, 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=322, start_offset=322, 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=324, start_offset=324, 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=326, start_offset=326, 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=328, start_offset=328, 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=100, arg=2, argval=344, argrepr='to L11', offset=336, start_offset=336, 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=340, start_offset=340, starts_line=False, line_number=25, label=None, positions=None, cache_info=None),
- Instruction(opname='RERAISE', opcode=102, arg=2, argval=2, argrepr='', offset=342, start_offset=342, 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=344, start_offset=344, 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=346, start_offset=346, 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=348, start_offset=348, 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=350, start_offset=350, 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=352, start_offset=352, starts_line=False, line_number=25, label=None, positions=None, cache_info=None),
- Instruction(opname='JUMP_BACKWARD_NO_INTERRUPT', opcode=75, arg=29, argval=298, argrepr='to L10', offset=354, start_offset=354, starts_line=False, line_number=25, label=None, positions=None, cache_info=None),
- Instruction(opname='COPY', opcode=59, arg=3, argval=3, argrepr='', offset=356, start_offset=356, 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=358, start_offset=358, starts_line=False, line_number=None, label=None, positions=None, cache_info=None),
- Instruction(opname='RERAISE', opcode=102, arg=1, argval=1, argrepr='', offset=360, start_offset=360, 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=362, start_offset=362, starts_line=False, line_number=None, label=None, positions=None, cache_info=None),
- Instruction(opname='LOAD_GLOBAL', opcode=89, arg=4, argval='ZeroDivisionError', argrepr='ZeroDivisionError', offset=364, start_offset=364, 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=374, start_offset=374, starts_line=False, line_number=22, label=None, positions=None, cache_info=None),
- Instruction(opname='POP_JUMP_IF_FALSE', opcode=97, arg=15, argval=410, argrepr='to L12', offset=376, start_offset=376, 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=380, start_offset=380, 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=382, start_offset=382, starts_line=False, line_number=22, label=None, positions=None, cache_info=None),
- Instruction(opname='LOAD_GLOBAL', opcode=89, arg=3, argval='print', argrepr='print + NULL', offset=384, start_offset=384, 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=81, arg=4, argval='Here we go, here we go, here we go...', argrepr="'Here we go, here we go, here we go...'", offset=394, start_offset=394, starts_line=False, line_number=23, label=None, positions=None, cache_info=None),
- Instruction(opname='CALL', opcode=51, arg=1, argval=1, argrepr='', offset=396, start_offset=396, 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=404, start_offset=404, 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=406, start_offset=406, starts_line=False, line_number=23, label=None, positions=None, cache_info=None),
- Instruction(opname='JUMP_BACKWARD_NO_INTERRUPT', opcode=75, arg=56, argval=298, argrepr='to L10', offset=408, start_offset=408, starts_line=False, line_number=23, label=None, positions=None, cache_info=None),
- Instruction(opname='RERAISE', opcode=102, arg=0, argval=0, argrepr='', offset=410, start_offset=410, starts_line=True, line_number=22, label=12, positions=None, cache_info=None),
- Instruction(opname='COPY', opcode=59, arg=3, argval=3, argrepr='', offset=412, start_offset=412, 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=414, start_offset=414, starts_line=False, line_number=None, label=None, positions=None, cache_info=None),
- Instruction(opname='RERAISE', opcode=102, arg=1, argval=1, argrepr='', offset=416, start_offset=416, 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=418, start_offset=418, starts_line=False, line_number=None, label=None, positions=None, cache_info=None),
- Instruction(opname='LOAD_GLOBAL', opcode=89, arg=3, argval='print', argrepr='print + NULL', offset=420, start_offset=420, 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=81, arg=5, argval="OK, now we're done", argrepr='"OK, now we\'re done"', offset=430, start_offset=430, starts_line=False, line_number=28, label=None, positions=None, cache_info=None),
- Instruction(opname='CALL', opcode=51, arg=1, argval=1, argrepr='', offset=432, start_offset=432, 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=440, start_offset=440, starts_line=False, line_number=28, label=None, positions=None, cache_info=None),
- Instruction(opname='RERAISE', opcode=102, arg=0, argval=0, argrepr='', offset=442, start_offset=442, starts_line=False, line_number=28, label=None, positions=None, cache_info=None),
- Instruction(opname='COPY', opcode=59, arg=3, argval=3, argrepr='', offset=444, start_offset=444, 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=446, start_offset=446, starts_line=False, line_number=None, label=None, positions=None, cache_info=None),
- Instruction(opname='RERAISE', opcode=102, arg=1, argval=1, argrepr='', offset=448, start_offset=448, starts_line=False, line_number=None, 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=109, 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=83, 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=91, 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=56, 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=97, 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=74, 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=83, 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=91, 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=56, 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=100, 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=74, 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=76, 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=89, 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=81, 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=91, 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=91, 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=83, 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=59, 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=92, 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=114, 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=114, 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=92, 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=109, 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=89, 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=81, 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=81, 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=81, 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=81, 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=89, 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=81, 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=81, 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=100, 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=102, 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=75, 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=59, 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=102, 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=89, 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=97, 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=89, 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=81, 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=75, 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=102, 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=59, 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=102, 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=89, 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=81, 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=102, 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=59, 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=102, 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
diff --git a/Lib/test/test_monitoring.py b/Lib/test/test_monitoring.py
index 43e3e56639db62..bea0e48883bf9a 100644
--- a/Lib/test/test_monitoring.py
+++ b/Lib/test/test_monitoring.py
@@ -1649,7 +1649,7 @@ def foo(n=0):
return None
in_loop = ('branch left', 'foo', 10, 16)
- exit_loop = ('branch right', 'foo', 10, 32)
+ exit_loop = ('branch right', 'foo', 10, 40)
self.check_events(foo, recorders = BRANCH_OFFSET_RECORDERS, expected = [
in_loop,
in_loop,
diff --git a/Lib/test/test_opcache.py b/Lib/test/test_opcache.py
index b80ccbf17f1ee6..72b845fcc8fdbf 100644
--- a/Lib/test/test_opcache.py
+++ b/Lib/test/test_opcache.py
@@ -1338,6 +1338,31 @@ def binary_op_add_unicode():
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(100):
+ 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")
+
+
@cpython_only
@requires_specialization_ft
def test_load_super_attr(self):
diff --git a/Misc/NEWS.d/next/Core_and_Builtins/2025-01-10-23-54-16.gh-issue-100239.ijOOUs.rst b/Misc/NEWS.d/next/Core_and_Builtins/2025-01-10-23-54-16.gh-issue-100239.ijOOUs.rst
new file mode 100644
index 00000000000000..f58c1fc767515e
--- /dev/null
+++ b/Misc/NEWS.d/next/Core_and_Builtins/2025-01-10-23-54-16.gh-issue-100239.ijOOUs.rst
@@ -0,0 +1,2 @@
+Add opcode ``BINARY_OP_EXTEND`` which executes a pair of functions (guard and
+specialization functions) accessed from the inline cache.
diff --git a/Python/bytecodes.c b/Python/bytecodes.c
index a906ded365650c..b1d61a8707bd4c 100644
--- a/Python/bytecodes.c
+++ b/Python/bytecodes.c
@@ -522,6 +522,7 @@ dummy_func(
BINARY_OP_SUBTRACT_FLOAT,
BINARY_OP_ADD_UNICODE,
// BINARY_OP_INPLACE_ADD_UNICODE, // See comments at that opcode.
+ BINARY_OP_EXTEND,
};
op(_GUARD_BOTH_INT, (left, right -- left, right)) {
@@ -587,11 +588,11 @@ dummy_func(
}
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);
@@ -659,11 +660,11 @@ dummy_func(
}
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);
@@ -689,7 +690,7 @@ dummy_func(
}
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
@@ -741,8 +742,34 @@ dummy_func(
#endif
}
+ 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);
+ EXIT_IF(!res);
+ }
+
+ 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 = d->action(left_o, right_o);
+ DECREF_INPUTS();
+ res = PyStackRef_FromPyObjectSteal(res_o);
+ }
+
+ 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/1 + _BINARY_OP_INPLACE_ADD_UNICODE;
+ _GUARD_BOTH_UNICODE + unused/5 + _BINARY_OP_INPLACE_ADD_UNICODE;
family(BINARY_SUBSCR, INLINE_CACHE_ENTRIES_BINARY_SUBSCR) = {
BINARY_SUBSCR_DICT,
@@ -4742,7 +4769,7 @@ dummy_func(
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)) {
diff --git a/Python/executor_cases.c.h b/Python/executor_cases.c.h
index cda01bb768c269..ad825881c8228c 100644
--- a/Python/executor_cases.c.h
+++ b/Python/executor_cases.c.h
@@ -899,6 +899,51 @@
break;
}
+ 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;
+ 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 = 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;
+ stack_pointer += -1;
+ assert(WITHIN_STACK_BOUNDS());
+ break;
+ }
+
case _BINARY_SUBSCR: {
_PyStackRef sub;
_PyStackRef container;
diff --git a/Python/generated_cases.c.h b/Python/generated_cases.c.h
index 81408380d6b2b8..dc90f75f2645e1 100644
--- a/Python/generated_cases.c.h
+++ b/Python/generated_cases.c.h
@@ -11,10 +11,10 @@
TARGET(BINARY_OP) {
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;
+ _Py_CODEUNIT* const this_instr = next_instr - 6;
(void)this_instr;
_PyStackRef lhs;
_PyStackRef rhs;
@@ -39,6 +39,7 @@
assert(NB_ADD <= oparg);
assert(oparg <= NB_INPLACE_XOR);
}
+ /* Skip 4 cache entries */
// _BINARY_OP
{
PyObject *lhs_o = PyStackRef_AsPyObjectBorrow(lhs);
@@ -60,9 +61,9 @@
TARGET(BINARY_OP_ADD_FLOAT) {
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;
@@ -75,7 +76,7 @@
DEOPT_IF(!PyFloat_CheckExact(left_o), BINARY_OP);
DEOPT_IF(!PyFloat_CheckExact(right_o), BINARY_OP);
}
- /* Skip 1 cache entry */
+ /* Skip 5 cache entries */
// _BINARY_OP_ADD_FLOAT
{
PyObject *left_o = PyStackRef_AsPyObjectBorrow(left);
@@ -98,9 +99,9 @@
TARGET(BINARY_OP_ADD_INT) {
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;
@@ -113,7 +114,7 @@
DEOPT_IF(!PyLong_CheckExact(left_o), BINARY_OP);
DEOPT_IF(!PyLong_CheckExact(right_o), BINARY_OP);
}
- /* Skip 1 cache entry */
+ /* Skip 5 cache entries */
// _BINARY_OP_ADD_INT
{
PyObject *left_o = PyStackRef_AsPyObjectBorrow(left);
@@ -135,9 +136,9 @@
TARGET(BINARY_OP_ADD_UNICODE) {
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;
@@ -150,7 +151,7 @@
DEOPT_IF(!PyUnicode_CheckExact(left_o), BINARY_OP);
DEOPT_IF(!PyUnicode_CheckExact(right_o), BINARY_OP);
}
- /* Skip 1 cache entry */
+ /* Skip 5 cache entries */
// _BINARY_OP_ADD_UNICODE
{
PyObject *left_o = PyStackRef_AsPyObjectBorrow(left);
@@ -170,11 +171,57 @@
DISPATCH();
}
+ TARGET(BINARY_OP_EXTEND) {
+ _Py_CODEUNIT* const 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);
+ DEOPT_IF(!res, 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;
+ stack_pointer += -1;
+ assert(WITHIN_STACK_BOUNDS());
+ DISPATCH();
+ }
+
TARGET(BINARY_OP_INPLACE_ADD_UNICODE) {
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
@@ -186,7 +233,7 @@
DEOPT_IF(!PyUnicode_CheckExact(left_o), BINARY_OP);
DEOPT_IF(!PyUnicode_CheckExact(right_o), BINARY_OP);
}
- /* Skip 1 cache entry */
+ /* Skip 5 cache entries */
// _BINARY_OP_INPLACE_ADD_UNICODE
{
PyObject *left_o = PyStackRef_AsPyObjectBorrow(left);
@@ -235,9 +282,9 @@
TARGET(BINARY_OP_MULTIPLY_FLOAT) {
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;
@@ -250,7 +297,7 @@
DEOPT_IF(!PyFloat_CheckExact(left_o), BINARY_OP);
DEOPT_IF(!PyFloat_CheckExact(right_o), BINARY_OP);
}
- /* Skip 1 cache entry */
+ /* Skip 5 cache entries */
// _BINARY_OP_MULTIPLY_FLOAT
{
PyObject *left_o = PyStackRef_AsPyObjectBorrow(left);
@@ -273,9 +320,9 @@
TARGET(BINARY_OP_MULTIPLY_INT) {
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;
@@ -288,7 +335,7 @@
DEOPT_IF(!PyLong_CheckExact(left_o), BINARY_OP);
DEOPT_IF(!PyLong_CheckExact(right_o), BINARY_OP);
}
- /* Skip 1 cache entry */
+ /* Skip 5 cache entries */
// _BINARY_OP_MULTIPLY_INT
{
PyObject *left_o = PyStackRef_AsPyObjectBorrow(left);
@@ -310,9 +357,9 @@
TARGET(BINARY_OP_SUBTRACT_FLOAT) {
frame->instr_ptr = next_instr;
- next_instr += 2;
+ next_instr += 6;
INSTRUCTION_STATS(BINARY_OP_SUBTRACT_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;
@@ -325,7 +372,7 @@
DEOPT_IF(!PyFloat_CheckExact(left_o), BINARY_OP);
DEOPT_IF(!PyFloat_CheckExact(right_o), BINARY_OP);
}
- /* Skip 1 cache entry */
+ /* Skip 5 cache entries */
// _BINARY_OP_SUBTRACT_FLOAT
{
PyObject *left_o = PyStackRef_AsPyObjectBorrow(left);
@@ -348,9 +395,9 @@
TARGET(BINARY_OP_SUBTRACT_INT) {
frame->instr_ptr = next_instr;
- next_instr += 2;
+ next_instr += 6;
INSTRUCTION_STATS(BINARY_OP_SUBTRACT_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;
@@ -363,7 +410,7 @@
DEOPT_IF(!PyLong_CheckExact(left_o), BINARY_OP);
DEOPT_IF(!PyLong_CheckExact(right_o), BINARY_OP);
}
- /* Skip 1 cache entry */
+ /* Skip 5 cache entries */
// _BINARY_OP_SUBTRACT_INT
{
PyObject *left_o = PyStackRef_AsPyObjectBorrow(left);
diff --git a/Python/opcode_targets.h b/Python/opcode_targets.h
index c5c008fcbe574e..cb6c33f01d3598 100644
--- a/Python/opcode_targets.h
+++ b/Python/opcode_targets.h
@@ -152,6 +152,7 @@ static void *opcode_targets[256] = {
&&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_SUBTRACT_FLOAT,
@@ -233,7 +234,6 @@ static void *opcode_targets[256] = {
&&_unknown_opcode,
&&_unknown_opcode,
&&_unknown_opcode,
- &&_unknown_opcode,
&&TARGET_INSTRUMENTED_END_FOR,
&&TARGET_INSTRUMENTED_POP_ITER,
&&TARGET_INSTRUMENTED_END_SEND,
diff --git a/Python/optimizer_cases.c.h b/Python/optimizer_cases.c.h
index aff4493fdc4dd7..90838d274a5e87 100644
--- a/Python/optimizer_cases.c.h
+++ b/Python/optimizer_cases.c.h
@@ -562,6 +562,19 @@
break;
}
+ case _GUARD_BINARY_OP_EXTEND: {
+ break;
+ }
+
+ case _BINARY_OP_EXTEND: {
+ _Py_UopsSymbol *res;
+ res = sym_new_not_null(ctx);
+ stack_pointer[-2] = res;
+ stack_pointer += -1;
+ assert(WITHIN_STACK_BOUNDS());
+ break;
+ }
+
case _BINARY_SUBSCR: {
_Py_UopsSymbol *res;
res = sym_new_not_null(ctx);
diff --git a/Python/specialize.c b/Python/specialize.c
index 8d9f19c8895187..09bfcd34b5a543 100644
--- a/Python/specialize.c
+++ b/Python/specialize.c
@@ -1174,7 +1174,7 @@ do_specialize_instance_load_attr(PyObject* owner, _Py_CODEUNIT* instr, PyObject*
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;
}
@@ -1254,7 +1254,7 @@ do_specialize_instance_load_attr(PyObject* owner, _Py_CODEUNIT* instr, PyObject*
#endif
write_u32(lm_cache->keys_version, version);
/* borrowed */
- write_obj(lm_cache->descr, descr);
+ write_ptr(lm_cache->descr, descr);
write_u32(lm_cache->type_version, tp_version);
specialize(instr, LOAD_ATTR_GETATTRIBUTE_OVERRIDDEN);
return 0;
@@ -1534,7 +1534,7 @@ specialize_class_load_attr(PyObject *owner, _Py_CODEUNIT *instr,
}
#endif
write_u32(cache->type_version, tp_version);
- write_obj(cache->descr, descr);
+ write_ptr(cache->descr, descr);
if (metaclass_check) {
write_u32(cache->keys_version, meta_version);
specialize(instr, LOAD_ATTR_CLASS_WITH_METACLASS_CHECK);
@@ -1642,7 +1642,7 @@ specialize_attr_loadclassattr(PyObject *owner, _Py_CODEUNIT *instr,
* working since Python 2.6 and it's battle-tested.
*/
write_u32(cache->type_version, tp_version);
- write_obj(cache->descr, descr);
+ write_ptr(cache->descr, descr);
return 1;
}
@@ -2412,6 +2412,92 @@ binary_op_fail_kind(int oparg, PyObject *lhs, PyObject *rhs)
}
#endif
+/** Binary Op Specialization Extensions */
+
+/* float-long */
+
+static int
+float_compactlong_guard(PyObject *lhs, PyObject *rhs)
+{
+ return (
+ PyFloat_CheckExact(lhs) &&
+ PyLong_CheckExact(rhs) &&
+ _PyLong_IsCompact((PyLongObject *)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 int
+compactlong_float_guard(PyObject *lhs, PyObject *rhs)
+{
+ return (
+ PyFloat_CheckExact(rhs) &&
+ PyLong_CheckExact(lhs) &&
+ _PyLong_IsCompact((PyLongObject *)lhs)
+ );
+}
+
+#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 float_compactlong_specs[NB_OPARG_LAST+1] = {
+ [NB_ADD] = {float_compactlong_guard, float_compactlong_add},
+ [NB_SUBTRACT] = {float_compactlong_guard, float_compactlong_subtract},
+ [NB_TRUE_DIVIDE] = {float_compactlong_guard, float_compactlong_true_div},
+ [NB_MULTIPLY] = {float_compactlong_guard, float_compactlong_multiply},
+};
+
+static _PyBinaryOpSpecializationDescr compactlong_float_specs[NB_OPARG_LAST+1] = {
+ [NB_ADD] = {compactlong_float_guard, compactlong_float_add},
+ [NB_SUBTRACT] = {compactlong_float_guard, compactlong_float_subtract},
+ [NB_TRUE_DIVIDE] = {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)
+{
+#define LOOKUP_SPEC(TABLE, OPARG) \
+ if ((TABLE)[(OPARG)].action) { \
+ if ((TABLE)[(OPARG)].guard(lhs, rhs)) { \
+ *descr = &((TABLE)[OPARG]); \
+ return 1; \
+ } \
+ }
+
+ LOOKUP_SPEC(compactlong_float_specs, oparg);
+ LOOKUP_SPEC(float_compactlong_specs, oparg);
+#undef LOOKUP_SPEC
+ return 0;
+}
+
void
_Py_Specialize_BinaryOp(_PyStackRef lhs_st, _PyStackRef rhs_st, _Py_CODEUNIT *instr,
int oparg, _PyStackRef *locals)
@@ -2420,6 +2506,12 @@ _Py_Specialize_BinaryOp(_PyStackRef lhs_st, _PyStackRef rhs_st, _Py_CODEUNIT *in
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:
@@ -2474,8 +2566,17 @@ _Py_Specialize_BinaryOp(_PyStackRef lhs_st, _PyStackRef rhs_st, _Py_CODEUNIT *in
}
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;
}
diff --git a/Tools/c-analyzer/cpython/ignored.tsv b/Tools/c-analyzer/cpython/ignored.tsv
index c8c30a7985aa2e..213165b06866b5 100644
--- a/Tools/c-analyzer/cpython/ignored.tsv
+++ b/Tools/c-analyzer/cpython/ignored.tsv
@@ -378,6 +378,8 @@ Python/pylifecycle.c - INTERPRETER_TRAMPOLINE_CODEDEF -
Python/pystate.c - initial -
Python/specialize.c - adaptive_opcodes -
Python/specialize.c - cache_requirements -
+Python/specialize.c - float_compactlong_specs -
+Python/specialize.c - compactlong_float_specs -
Python/stdlib_module_names.h - _Py_stdlib_module_names -
Python/sysmodule.c - perf_map_state -
Python/sysmodule.c - _PySys_ImplCacheTag -
diff --git a/Tools/cases_generator/parsing.py b/Tools/cases_generator/parsing.py
index de31d9b232f9df..41b36b6a546360 100644
--- a/Tools/cases_generator/parsing.py
+++ b/Tools/cases_generator/parsing.py
@@ -357,9 +357,12 @@ def uops(self) -> list[UOp] | None:
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}"
1
0
https://github.com/python/cpython/commit/e81fe940c9bd092f6de558fa965100502b…
commit: e81fe940c9bd092f6de558fa965100502b78da0f
branch: main
author: Irit Katriel <1055913+iritkatriel(a)users.noreply.github.com>
committer: iritkatriel <1055913+iritkatriel(a)users.noreply.github.com>
date: 2025-01-16T13:15:52Z
summary:
gh-119786: added InternalDocs/generators.md (#128524)
files:
M InternalDocs/README.md
M InternalDocs/generators.md
diff --git a/InternalDocs/README.md b/InternalDocs/README.md
index 794b4f3c6aad42..4502902307cd5c 100644
--- a/InternalDocs/README.md
+++ b/InternalDocs/README.md
@@ -25,7 +25,7 @@ Runtime Objects
- [Code Objects](code_objects.md)
-- [Generators (coming soon)](generators.md)
+- [Generators](generators.md)
- [Frames](frames.md)
diff --git a/InternalDocs/generators.md b/InternalDocs/generators.md
index afa8b8f4bb8040..608bd215aae65a 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
+fram 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-ex….
+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)).
-<!--
-- Generators, async functions, async generators, and ``yield from`` (next, send, throw, close; and await; and how this code breaks the interpreter abstraction)
--->
+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`.
1
0
https://github.com/python/cpython/commit/3193cb5ef87b77158d5c9bef99ae445cb8…
commit: 3193cb5ef87b77158d5c9bef99ae445cb82727de
branch: main
author: Victor Stinner <vstinner(a)python.org>
committer: vstinner <vstinner(a)python.org>
date: 2025-01-16T13:53:18+01:00
summary:
gh-128679: Fix tracemalloc.stop() race conditions (#128893)
tracemalloc_alloc(), tracemalloc_realloc(), tracemalloc_free(),
_PyTraceMalloc_TraceRef() and _PyTraceMalloc_GetMemory() now check
'tracemalloc_config.tracing' after calling TABLES_LOCK().
_PyTraceMalloc_TraceRef() now always returns 0.
files:
A Misc/NEWS.d/next/Library/2025-01-15-21-41-51.gh-issue-128679.tq10F2.rst
M Lib/test/test_tracemalloc.py
M Modules/_testcapimodule.c
M Python/tracemalloc.c
diff --git a/Lib/test/test_tracemalloc.py b/Lib/test/test_tracemalloc.py
index 5755f7697de91a..da2db28775578a 100644
--- a/Lib/test/test_tracemalloc.py
+++ b/Lib/test/test_tracemalloc.py
@@ -7,8 +7,9 @@
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
@@ -952,7 +953,6 @@ def check_env_var_invalid(self, nframe):
return
self.fail(f"unexpected output: {stderr!a}")
-
def test_env_var_invalid(self):
for nframe in INVALID_NFRAME:
with self.subTest(nframe=nframe):
@@ -1101,6 +1101,12 @@ def test_stop_untrack(self):
with self.assertRaises(RuntimeError):
self.untrack()
+ @unittest.skipIf(_testcapi is None, 'need _testcapi')
+ @threading_helper.requires_working_threading()
+ def test_tracemalloc_track_race(self):
+ # gh-128679: Test fix for tracemalloc.stop() race condition
+ _testcapi.tracemalloc_track_race()
+
if __name__ == "__main__":
unittest.main()
diff --git a/Misc/NEWS.d/next/Library/2025-01-15-21-41-51.gh-issue-128679.tq10F2.rst b/Misc/NEWS.d/next/Library/2025-01-15-21-41-51.gh-issue-128679.tq10F2.rst
new file mode 100644
index 00000000000000..5c108da5703c00
--- /dev/null
+++ b/Misc/NEWS.d/next/Library/2025-01-15-21-41-51.gh-issue-128679.tq10F2.rst
@@ -0,0 +1,3 @@
+:mod:`tracemalloc`: Fix race conditions when :func:`tracemalloc.stop` is
+called by a thread, while other threads are tracing memory allocations.
+Patch by Victor Stinner.
diff --git a/Modules/_testcapimodule.c b/Modules/_testcapimodule.c
index a0a1f8af6710a3..7d304add5999d1 100644
--- a/Modules/_testcapimodule.c
+++ b/Modules/_testcapimodule.c
@@ -3435,6 +3435,104 @@ code_offset_to_line(PyObject* self, PyObject* const* args, Py_ssize_t nargsf)
return PyLong_FromInt32(PyCode_Addr2Line(code, offset));
}
+
+static void
+tracemalloc_track_race_thread(void *data)
+{
+ PyTraceMalloc_Track(123, 10, 1);
+
+ 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 TestMethods[] = {
{"set_errno", set_errno, METH_VARARGS},
{"test_config", test_config, METH_NOARGS},
@@ -3578,6 +3676,7 @@ static PyMethodDef TestMethods[] = {
{"type_freeze", type_freeze, METH_VARARGS},
{"test_atexit", test_atexit, METH_NOARGS},
{"code_offset_to_line", _PyCFunction_CAST(code_offset_to_line), METH_FASTCALL},
+ {"tracemalloc_track_race", tracemalloc_track_race, METH_NOARGS},
{NULL, NULL} /* sentinel */
};
diff --git a/Python/tracemalloc.c b/Python/tracemalloc.c
index 68b641c51868b9..919c564ee72967 100644
--- a/Python/tracemalloc.c
+++ b/Python/tracemalloc.c
@@ -567,11 +567,14 @@ tracemalloc_alloc(int need_gil, int use_calloc,
}
TABLES_LOCK();
- if (ADD_TRACE(ptr, nelem * elsize) < 0) {
- // Failed to allocate a trace for the new memory block
- alloc->free(alloc->ctx, ptr);
- ptr = 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) {
@@ -614,6 +617,11 @@ tracemalloc_realloc(int need_gil, void *ctx, void *ptr, size_t new_size)
}
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
@@ -646,6 +654,7 @@ tracemalloc_realloc(int need_gil, void *ctx, void *ptr, size_t new_size)
}
}
+unlock:
TABLES_UNLOCK();
if (need_gil) {
PyGILState_Release(gil_state);
@@ -674,7 +683,12 @@ tracemalloc_free(void *ctx, void *ptr)
}
TABLES_LOCK();
- REMOVE_TRACE(ptr);
+
+ if (tracemalloc_config.tracing) {
+ REMOVE_TRACE(ptr);
+ }
+ // else: gh-128679: tracemalloc.stop() was called by another thread
+
TABLES_UNLOCK();
}
@@ -1312,8 +1326,9 @@ _PyTraceMalloc_TraceRef(PyObject *op, PyRefTracerEvent event,
assert(PyGILState_Check());
TABLES_LOCK();
- int result = -1;
- assert(tracemalloc_config.tracing);
+ if (!tracemalloc_config.tracing) {
+ goto done;
+ }
PyTypeObject *type = Py_TYPE(op);
const size_t presize = _PyType_PreHeaderSize(type);
@@ -1325,13 +1340,13 @@ _PyTraceMalloc_TraceRef(PyObject *op, PyRefTracerEvent event,
traceback_t *traceback = traceback_new();
if (traceback != NULL) {
trace->traceback = traceback;
- result = 0;
}
}
/* else: cannot track the object, its memory block size is unknown */
+done:
TABLES_UNLOCK();
- return result;
+ return 0;
}
@@ -1472,13 +1487,19 @@ int _PyTraceMalloc_GetTracebackLimit(void)
size_t
_PyTraceMalloc_GetMemory(void)
{
- size_t 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_t size;
+ if (tracemalloc_config.tracing) {
+ size = _Py_hashtable_size(tracemalloc_tracebacks);
+ size += _Py_hashtable_size(tracemalloc_filenames);
+
+ size += _Py_hashtable_size(tracemalloc_traces);
+ _Py_hashtable_foreach(tracemalloc_domains,
+ tracemalloc_get_tracemalloc_memory_cb, &size);
+ }
+ else {
+ size = 0;
+ }
TABLES_UNLOCK();
return size;
}
1
0
[3.12] gh-128017: Make a note that sys variables are read-only (GH-128887) (#128909)
by vstinner Jan. 16, 2025
by vstinner Jan. 16, 2025
Jan. 16, 2025
https://github.com/python/cpython/commit/1c85f1bc4424b1ed43f1594442e4102209…
commit: 1c85f1bc4424b1ed43f1594442e41022099f05e3
branch: 3.12
author: Miss Islington (bot) <31488909+miss-islington(a)users.noreply.github.com>
committer: vstinner <vstinner(a)python.org>
date: 2025-01-16T10:23:48Z
summary:
[3.12] gh-128017: Make a note that sys variables are read-only (GH-128887) (#128909)
gh-128017: Make a note that sys variables are read-only (GH-128887)
(cherry picked from commit 313b96eb8b8d0ad3bac58d633822a0a3705ce60b)
Co-authored-by: Srinivas Reddy Thatiparthy (తాటిపర్తి శ్రీనివాస్ రెడ్డి) <thatiparthysreenivas(a)gmail.com>
files:
M Doc/library/sys.rst
diff --git a/Doc/library/sys.rst b/Doc/library/sys.rst
index 90c794e3f3c58d..70844d4d26b1cb 100644
--- a/Doc/library/sys.rst
+++ b/Doc/library/sys.rst
@@ -8,7 +8,7 @@
This module provides access to some variables used or maintained by the
interpreter and to functions that interact strongly with the interpreter. It is
-always available.
+always available. Unless explicitly noted otherwise, all variables are read-only.
.. data:: abiflags
1
0
Jan. 16, 2025
https://github.com/python/cpython/commit/313b96eb8b8d0ad3bac58d633822a0a370…
commit: 313b96eb8b8d0ad3bac58d633822a0a3705ce60b
branch: main
author: Srinivas Reddy Thatiparthy (తాటిపర్తి శ్రీనివాస్ రెడ్డి) <thatiparthysreenivas(a)gmail.com>
committer: vstinner <vstinner(a)python.org>
date: 2025-01-16T11:17:03+01:00
summary:
gh-128017: Make a note that sys variables are read-only (#128887)
files:
M Doc/library/sys.rst
diff --git a/Doc/library/sys.rst b/Doc/library/sys.rst
index dd6293c722e7ad..151fd60532048a 100644
--- a/Doc/library/sys.rst
+++ b/Doc/library/sys.rst
@@ -8,7 +8,7 @@
This module provides access to some variables used or maintained by the
interpreter and to functions that interact strongly with the interpreter. It is
-always available.
+always available. Unless explicitly noted otherwise, all variables are read-only.
.. data:: abiflags
1
0
[3.12] gh-128816: Fix warnings in test_doctest (GH-128817) (GH-128871)
by serhiy-storchaka Jan. 16, 2025
by serhiy-storchaka Jan. 16, 2025
Jan. 16, 2025
https://github.com/python/cpython/commit/45b89bf0da69a1193e5c79029a11876351…
commit: 45b89bf0da69a1193e5c79029a118763512a1d04
branch: 3.12
author: Miss Islington (bot) <31488909+miss-islington(a)users.noreply.github.com>
committer: serhiy-storchaka <storchaka(a)gmail.com>
date: 2025-01-16T09:09:13Z
summary:
[3.12] gh-128816: Fix warnings in test_doctest (GH-128817) (GH-128871)
* Fix a deprecation warning for using importlib.resources.abc.ResourceReader.
* Fix an import warning when importing readline (if it has not yet been imported).
(cherry picked from commit 599be687ec7327c30c6469cf743aa4ee9e82232d)
Co-authored-by: Thomas Grainger <tagrain(a)gmail.com>
files:
M Lib/test/test_doctest/test_doctest.py
diff --git a/Lib/test/test_doctest/test_doctest.py b/Lib/test/test_doctest/test_doctest.py
index 069418453f1f48..62d474633a6273 100644
--- a/Lib/test/test_doctest/test_doctest.py
+++ b/Lib/test/test_doctest/test_doctest.py
@@ -2780,7 +2780,7 @@ def test_testfile(): r"""
>>> sys.argv = save_argv
"""
-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)
@@ -2789,6 +2789,12 @@ def get_data(self, path):
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):
1
0
[3.13] gh-128816: Fix warnings in test_doctest (GH-128817) (GH-128870)
by serhiy-storchaka Jan. 16, 2025
by serhiy-storchaka Jan. 16, 2025
Jan. 16, 2025
https://github.com/python/cpython/commit/c927fd9d2514adb0b0499c222062c77da7…
commit: c927fd9d2514adb0b0499c222062c77da79be146
branch: 3.13
author: Miss Islington (bot) <31488909+miss-islington(a)users.noreply.github.com>
committer: serhiy-storchaka <storchaka(a)gmail.com>
date: 2025-01-16T08:57:14Z
summary:
[3.13] gh-128816: Fix warnings in test_doctest (GH-128817) (GH-128870)
* Fix a deprecation warning for using importlib.resources.abc.ResourceReader.
* Fix an import warning when importing readline (if it has not yet been imported).
(cherry picked from commit 599be687ec7327c30c6469cf743aa4ee9e82232d)
Co-authored-by: Thomas Grainger <tagrain(a)gmail.com>
files:
M Lib/test/test_doctest/test_doctest.py
diff --git a/Lib/test/test_doctest/test_doctest.py b/Lib/test/test_doctest/test_doctest.py
index 286c3ecfbc9239..7da6b983359041 100644
--- a/Lib/test/test_doctest/test_doctest.py
+++ b/Lib/test/test_doctest/test_doctest.py
@@ -2872,7 +2872,7 @@ def test_testfile(): r"""
>>> _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)
@@ -2881,6 +2881,12 @@ def get_data(self, path):
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):
1
0
Jan. 15, 2025
https://github.com/python/cpython/commit/d05140f9f77d7dfc753dd1e5ac3a5962aa…
commit: d05140f9f77d7dfc753dd1e5ac3a5962aaa03eff
branch: main
author: Thomas Grainger <tagrain(a)gmail.com>
committer: brettcannon <brett(a)python.org>
date: 2025-01-15T21:13:59Z
summary:
gh-121604: fix ResourceLoader deprecation warning message (GH-128859)
files:
M Lib/importlib/abc.py
diff --git a/Lib/importlib/abc.py b/Lib/importlib/abc.py
index bb2837d38d83f1..29f01f77eff4a0 100644
--- a/Lib/importlib/abc.py
+++ b/Lib/importlib/abc.py
@@ -74,7 +74,7 @@ def __init__(self):
import warnings
warnings.warn('importlib.abc.ResourceLoader is deprecated in '
'favour of supporting resource loading through '
- 'importlib.resources.abc.ResourceReader.',
+ 'importlib.resources.abc.TraversableResources.',
DeprecationWarning, stacklevel=2)
super().__init__()
1
0
Jan. 15, 2025
https://github.com/python/cpython/commit/5eee2fe2b05c1a2836184e047fbd417694…
commit: 5eee2fe2b05c1a2836184e047fbd4176945cbf10
branch: main
author: Irit Katriel <1055913+iritkatriel(a)users.noreply.github.com>
committer: iritkatriel <1055913+iritkatriel(a)users.noreply.github.com>
date: 2025-01-15T21:02:32Z
summary:
gh-128891: add specialized opcodes to opcode.opname (#128892)
files:
A Misc/NEWS.d/next/Library/2025-01-15-19-32-23.gh-issue-128891.ojUxKo.rst
M Lib/opcode.py
M Lib/test/test__opcode.py
M Lib/test/test_dis.py
diff --git a/Lib/opcode.py b/Lib/opcode.py
index 974f4d35e2a524..aba66153af1b2e 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 = ('<', '<=', '==', '!=', '>', '>=')
diff --git a/Lib/test/test__opcode.py b/Lib/test/test__opcode.py
index d5cf014d40daf8..95e09500df51d0 100644
--- a/Lib/test/test__opcode.py
+++ b/Lib/test/test__opcode.py
@@ -38,6 +38,13 @@ def test_is_valid(self):
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]:
diff --git a/Lib/test/test_dis.py b/Lib/test/test_dis.py
index ed8bd6fa20880b..8afe9653f19f6e 100644
--- a/Lib/test/test_dis.py
+++ b/Lib/test/test_dis.py
@@ -999,12 +999,14 @@ def test_boundaries(self):
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)
diff --git a/Misc/NEWS.d/next/Library/2025-01-15-19-32-23.gh-issue-128891.ojUxKo.rst b/Misc/NEWS.d/next/Library/2025-01-15-19-32-23.gh-issue-128891.ojUxKo.rst
new file mode 100644
index 00000000000000..79d845bbab7cfc
--- /dev/null
+++ b/Misc/NEWS.d/next/Library/2025-01-15-19-32-23.gh-issue-128891.ojUxKo.rst
@@ -0,0 +1 @@
+Add specialized opcodes to ``opcode.opname``.
1
0