From 3b04c79a87c6d9f3a5502ecf97fe3b71ea0c31c3 Mon Sep 17 00:00:00 2001 From: Kumar Aditya Date: Wed, 17 Dec 2025 14:13:46 +0530 Subject: [PATCH 1/5] optimize for list --- Include/internal/pycore_magic_number.h | 2 +- Include/internal/pycore_opcode_utils.h | 3 ++- Lib/opcode.py | 2 +- Lib/test/test_builtin.py | 27 ++++++++++++++------------ Python/codegen.c | 11 ++++++++--- Python/pylifecycle.c | 1 + 6 files changed, 28 insertions(+), 18 deletions(-) diff --git a/Include/internal/pycore_magic_number.h b/Include/internal/pycore_magic_number.h index 2fb46a6df50bb3..58318f137c923d 100644 --- a/Include/internal/pycore_magic_number.h +++ b/Include/internal/pycore_magic_number.h @@ -300,7 +300,7 @@ PC/launcher.c must also be updated. */ -#define PYC_MAGIC_NUMBER 3656 +#define PYC_MAGIC_NUMBER 3657 /* 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_utils.h b/Include/internal/pycore_opcode_utils.h index 79a1a242556a52..e9fa546a6892d7 100644 --- a/Include/internal/pycore_opcode_utils.h +++ b/Include/internal/pycore_opcode_utils.h @@ -73,7 +73,8 @@ extern "C" { #define CONSTANT_BUILTIN_TUPLE 2 #define CONSTANT_BUILTIN_ALL 3 #define CONSTANT_BUILTIN_ANY 4 -#define NUM_COMMON_CONSTANTS 5 +#define CONSTANT_BUILTIN_LIST 5 +#define NUM_COMMON_CONSTANTS 6 /* Values used in the oparg for RESUME */ #define RESUME_AT_FUNC_START 0 diff --git a/Lib/opcode.py b/Lib/opcode.py index 0e9520b6832499..d2ed711e1ad09c 100644 --- a/Lib/opcode.py +++ b/Lib/opcode.py @@ -40,7 +40,7 @@ _intrinsic_2_descs = _opcode.get_intrinsic2_descs() _special_method_names = _opcode.get_special_method_names() _common_constants = [builtins.AssertionError, builtins.NotImplementedError, - builtins.tuple, builtins.all, builtins.any] + builtins.tuple, builtins.all, builtins.any, builtins.list] _nb_ops = _opcode.get_nb_ops() hascompare = [opmap["COMPARE_OP"]] diff --git a/Lib/test/test_builtin.py b/Lib/test/test_builtin.py index ce60a5d095dd52..4d829b564c54a4 100644 --- a/Lib/test/test_builtin.py +++ b/Lib/test/test_builtin.py @@ -246,7 +246,7 @@ def test_any(self): S = [10, 20, 30] self.assertEqual(any(x > 42 for x in S), False) - def test_all_any_tuple_optimization(self): + def test_all_any_tuple_list_optimization(self): def f_all(): return all(x-2 for x in [1,2,3]) @@ -256,7 +256,10 @@ def f_any(): def f_tuple(): return tuple(2*x for x in [1,2,3]) - funcs = [f_all, f_any, f_tuple] + def f_list(): + return list(2*x for x in [1,2,3]) + + funcs = [f_all, f_any, f_tuple, f_list] for f in funcs: # check that generator code object is not duplicated @@ -266,33 +269,33 @@ def f_tuple(): # check the overriding the builtins works - global all, any, tuple - saved = all, any, tuple + global all, any, tuple, list + saved = all, any, tuple, list try: all = lambda x : "all" any = lambda x : "any" tuple = lambda x : "tuple" + list = lambda x : "list" overridden_outputs = [f() for f in funcs] finally: - all, any, tuple = saved - - self.assertEqual(overridden_outputs, ['all', 'any', 'tuple']) + all, any, tuple, list = saved + self.assertEqual(overridden_outputs, ['all', 'any', 'tuple', 'list']) # Now repeat, overriding the builtins module as well - saved = all, any, tuple + saved = all, any, tuple, list try: builtins.all = all = lambda x : "all" builtins.any = any = lambda x : "any" builtins.tuple = tuple = lambda x : "tuple" + builtins.list = list = lambda x : "list" overridden_outputs = [f() for f in funcs] finally: - all, any, tuple = saved - builtins.all, builtins.any, builtins.tuple = saved - - self.assertEqual(overridden_outputs, ['all', 'any', 'tuple']) + all, any, tuple, list = saved + builtins.all, builtins.any, builtins.tuple, builtins.list = saved + self.assertEqual(overridden_outputs, ['all', 'any', 'tuple', 'list']) def test_ascii(self): self.assertEqual(ascii(''), '\'\'') diff --git a/Python/codegen.c b/Python/codegen.c index c4109fcaa48dbe..5219118ea2caac 100644 --- a/Python/codegen.c +++ b/Python/codegen.c @@ -3892,6 +3892,9 @@ maybe_optimize_function_call(compiler *c, expr_ty e, jump_target_label end) else if (_PyUnicode_EqualToASCIIString(func->v.Name.id, "tuple")) { const_oparg = CONSTANT_BUILTIN_TUPLE; } + else if (_PyUnicode_EqualToASCIIString(func->v.Name.id, "list")) { + const_oparg = CONSTANT_BUILTIN_LIST; + } if (const_oparg != -1) { ADDOP_I(c, loc, COPY, 1); // the function ADDOP_I(c, loc, LOAD_COMMON_CONSTANT, const_oparg); @@ -3899,7 +3902,7 @@ maybe_optimize_function_call(compiler *c, expr_ty e, jump_target_label end) ADDOP_JUMP(c, loc, POP_JUMP_IF_FALSE, skip_optimization); ADDOP(c, loc, POP_TOP); - if (const_oparg == CONSTANT_BUILTIN_TUPLE) { + if (const_oparg == CONSTANT_BUILTIN_TUPLE || const_oparg == CONSTANT_BUILTIN_LIST) { ADDOP_I(c, loc, BUILD_LIST, 0); } expr_ty generator_exp = asdl_seq_GET(args, 0); @@ -3911,7 +3914,7 @@ maybe_optimize_function_call(compiler *c, expr_ty e, jump_target_label end) ADDOP(c, loc, PUSH_NULL); // Push NULL index for loop USE_LABEL(c, loop); ADDOP_JUMP(c, loc, FOR_ITER, cleanup); - if (const_oparg == CONSTANT_BUILTIN_TUPLE) { + if (const_oparg == CONSTANT_BUILTIN_TUPLE || const_oparg == CONSTANT_BUILTIN_LIST) { ADDOP_I(c, loc, LIST_APPEND, 3); ADDOP_JUMP(c, loc, JUMP, loop); } @@ -3921,7 +3924,7 @@ maybe_optimize_function_call(compiler *c, expr_ty e, jump_target_label end) } ADDOP(c, NO_LOCATION, POP_ITER); - if (const_oparg != CONSTANT_BUILTIN_TUPLE) { + if (const_oparg != CONSTANT_BUILTIN_TUPLE && const_oparg != CONSTANT_BUILTIN_LIST) { ADDOP_LOAD_CONST(c, loc, initial_res == Py_True ? Py_False : Py_True); } ADDOP_JUMP(c, loc, JUMP, end); @@ -3931,6 +3934,8 @@ maybe_optimize_function_call(compiler *c, expr_ty e, jump_target_label end) ADDOP(c, NO_LOCATION, POP_ITER); if (const_oparg == CONSTANT_BUILTIN_TUPLE) { ADDOP_I(c, loc, CALL_INTRINSIC_1, INTRINSIC_LIST_TO_TUPLE); + } else if (const_oparg == CONSTANT_BUILTIN_LIST) { + // result is already a list } else { ADDOP_LOAD_CONST(c, loc, initial_res); diff --git a/Python/pylifecycle.c b/Python/pylifecycle.c index 2527dca71d774e..024996a9edd339 100644 --- a/Python/pylifecycle.c +++ b/Python/pylifecycle.c @@ -829,6 +829,7 @@ pycore_init_builtins(PyThreadState *tstate) interp->common_consts[CONSTANT_BUILTIN_TUPLE] = (PyObject*)&PyTuple_Type; interp->common_consts[CONSTANT_BUILTIN_ALL] = all; interp->common_consts[CONSTANT_BUILTIN_ANY] = any; + interp->common_consts[CONSTANT_BUILTIN_LIST] = (PyObject*)&PyList_Type; for (int i=0; i < NUM_COMMON_CONSTANTS; i++) { assert(interp->common_consts[i] != NULL); From 99fb67b9b29f75d0e33034603ffe616b9b117222 Mon Sep 17 00:00:00 2001 From: Kumar Aditya Date: Wed, 17 Dec 2025 14:34:51 +0530 Subject: [PATCH 2/5] optimize for sets --- Include/internal/pycore_opcode_utils.h | 3 ++- Lib/opcode.py | 3 ++- Lib/test/test_builtin.py | 25 +++++++++++++++---------- Python/codegen.c | 14 +++++++++++++- Python/pylifecycle.c | 1 + 5 files changed, 33 insertions(+), 13 deletions(-) diff --git a/Include/internal/pycore_opcode_utils.h b/Include/internal/pycore_opcode_utils.h index e9fa546a6892d7..e4d859fcc47d02 100644 --- a/Include/internal/pycore_opcode_utils.h +++ b/Include/internal/pycore_opcode_utils.h @@ -74,7 +74,8 @@ extern "C" { #define CONSTANT_BUILTIN_ALL 3 #define CONSTANT_BUILTIN_ANY 4 #define CONSTANT_BUILTIN_LIST 5 -#define NUM_COMMON_CONSTANTS 6 +#define CONSTANT_BUILTIN_SET 6 +#define NUM_COMMON_CONSTANTS 7 /* Values used in the oparg for RESUME */ #define RESUME_AT_FUNC_START 0 diff --git a/Lib/opcode.py b/Lib/opcode.py index d2ed711e1ad09c..d8374c45481a94 100644 --- a/Lib/opcode.py +++ b/Lib/opcode.py @@ -40,7 +40,8 @@ _intrinsic_2_descs = _opcode.get_intrinsic2_descs() _special_method_names = _opcode.get_special_method_names() _common_constants = [builtins.AssertionError, builtins.NotImplementedError, - builtins.tuple, builtins.all, builtins.any, builtins.list] + builtins.tuple, builtins.all, builtins.any, builtins.list, + builtins.set] _nb_ops = _opcode.get_nb_ops() hascompare = [opmap["COMPARE_OP"]] diff --git a/Lib/test/test_builtin.py b/Lib/test/test_builtin.py index 4d829b564c54a4..7b69374b1868d1 100644 --- a/Lib/test/test_builtin.py +++ b/Lib/test/test_builtin.py @@ -246,7 +246,7 @@ def test_any(self): S = [10, 20, 30] self.assertEqual(any(x > 42 for x in S), False) - def test_all_any_tuple_list_optimization(self): + def test_all_any_tuple_list_set_optimization(self): def f_all(): return all(x-2 for x in [1,2,3]) @@ -259,7 +259,10 @@ def f_tuple(): def f_list(): return list(2*x for x in [1,2,3]) - funcs = [f_all, f_any, f_tuple, f_list] + def f_set(): + return set(2*x for x in [1,2,3]) + + funcs = [f_all, f_any, f_tuple, f_list, f_set] for f in funcs: # check that generator code object is not duplicated @@ -269,33 +272,35 @@ def f_list(): # check the overriding the builtins works - global all, any, tuple, list - saved = all, any, tuple, list + global all, any, tuple, list, set + saved = all, any, tuple, list, set try: all = lambda x : "all" any = lambda x : "any" tuple = lambda x : "tuple" list = lambda x : "list" + set = lambda x : "set" overridden_outputs = [f() for f in funcs] finally: - all, any, tuple, list = saved + all, any, tuple, list, set = saved - self.assertEqual(overridden_outputs, ['all', 'any', 'tuple', 'list']) + self.assertEqual(overridden_outputs, ['all', 'any', 'tuple', 'list', 'set']) # Now repeat, overriding the builtins module as well - saved = all, any, tuple, list + saved = all, any, tuple, list, set try: builtins.all = all = lambda x : "all" builtins.any = any = lambda x : "any" builtins.tuple = tuple = lambda x : "tuple" builtins.list = list = lambda x : "list" + builtins.set = set = lambda x : "set" overridden_outputs = [f() for f in funcs] finally: - all, any, tuple, list = saved - builtins.all, builtins.any, builtins.tuple, builtins.list = saved + all, any, tuple, list, set = saved + builtins.all, builtins.any, builtins.tuple, builtins.list, builtins.set = saved - self.assertEqual(overridden_outputs, ['all', 'any', 'tuple', 'list']) + self.assertEqual(overridden_outputs, ['all', 'any', 'tuple', 'list', 'set']) def test_ascii(self): self.assertEqual(ascii(''), '\'\'') diff --git a/Python/codegen.c b/Python/codegen.c index 5219118ea2caac..acd8d84bc9ec6d 100644 --- a/Python/codegen.c +++ b/Python/codegen.c @@ -3895,6 +3895,9 @@ maybe_optimize_function_call(compiler *c, expr_ty e, jump_target_label end) else if (_PyUnicode_EqualToASCIIString(func->v.Name.id, "list")) { const_oparg = CONSTANT_BUILTIN_LIST; } + else if (_PyUnicode_EqualToASCIIString(func->v.Name.id, "set")) { + const_oparg = CONSTANT_BUILTIN_SET; + } if (const_oparg != -1) { ADDOP_I(c, loc, COPY, 1); // the function ADDOP_I(c, loc, LOAD_COMMON_CONSTANT, const_oparg); @@ -3904,6 +3907,8 @@ maybe_optimize_function_call(compiler *c, expr_ty e, jump_target_label end) if (const_oparg == CONSTANT_BUILTIN_TUPLE || const_oparg == CONSTANT_BUILTIN_LIST) { ADDOP_I(c, loc, BUILD_LIST, 0); + } else if (const_oparg == CONSTANT_BUILTIN_SET) { + ADDOP_I(c, loc, BUILD_SET, 0); } expr_ty generator_exp = asdl_seq_GET(args, 0); VISIT(c, expr, generator_exp); @@ -3917,6 +3922,9 @@ maybe_optimize_function_call(compiler *c, expr_ty e, jump_target_label end) if (const_oparg == CONSTANT_BUILTIN_TUPLE || const_oparg == CONSTANT_BUILTIN_LIST) { ADDOP_I(c, loc, LIST_APPEND, 3); ADDOP_JUMP(c, loc, JUMP, loop); + } else if (const_oparg == CONSTANT_BUILTIN_SET) { + ADDOP_I(c, loc, SET_ADD, 3); + ADDOP_JUMP(c, loc, JUMP, loop); } else { ADDOP(c, loc, TO_BOOL); @@ -3924,7 +3932,9 @@ maybe_optimize_function_call(compiler *c, expr_ty e, jump_target_label end) } ADDOP(c, NO_LOCATION, POP_ITER); - if (const_oparg != CONSTANT_BUILTIN_TUPLE && const_oparg != CONSTANT_BUILTIN_LIST) { + if (const_oparg != CONSTANT_BUILTIN_TUPLE && + const_oparg != CONSTANT_BUILTIN_LIST && + const_oparg != CONSTANT_BUILTIN_SET) { ADDOP_LOAD_CONST(c, loc, initial_res == Py_True ? Py_False : Py_True); } ADDOP_JUMP(c, loc, JUMP, end); @@ -3936,6 +3946,8 @@ maybe_optimize_function_call(compiler *c, expr_ty e, jump_target_label end) ADDOP_I(c, loc, CALL_INTRINSIC_1, INTRINSIC_LIST_TO_TUPLE); } else if (const_oparg == CONSTANT_BUILTIN_LIST) { // result is already a list + } else if (const_oparg == CONSTANT_BUILTIN_SET) { + // result is already a set } else { ADDOP_LOAD_CONST(c, loc, initial_res); diff --git a/Python/pylifecycle.c b/Python/pylifecycle.c index 024996a9edd339..ea4a242e5fe699 100644 --- a/Python/pylifecycle.c +++ b/Python/pylifecycle.c @@ -830,6 +830,7 @@ pycore_init_builtins(PyThreadState *tstate) interp->common_consts[CONSTANT_BUILTIN_ALL] = all; interp->common_consts[CONSTANT_BUILTIN_ANY] = any; interp->common_consts[CONSTANT_BUILTIN_LIST] = (PyObject*)&PyList_Type; + interp->common_consts[CONSTANT_BUILTIN_SET] = (PyObject*)&PySet_Type; for (int i=0; i < NUM_COMMON_CONSTANTS; i++) { assert(interp->common_consts[i] != NULL); From dcf895093314d123f4f79f525837b4b15e1aaad1 Mon Sep 17 00:00:00 2001 From: Kumar Aditya Date: Wed, 17 Dec 2025 14:37:04 +0530 Subject: [PATCH 3/5] add comment --- Include/internal/pycore_magic_number.h | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/Include/internal/pycore_magic_number.h b/Include/internal/pycore_magic_number.h index 58318f137c923d..119bcdd76ce5ee 100644 --- a/Include/internal/pycore_magic_number.h +++ b/Include/internal/pycore_magic_number.h @@ -287,7 +287,7 @@ Known values: Python 3.15a1 3654 (Fix missing exception handlers in logical expression) Python 3.15a1 3655 (Fix miscompilation of some module-level annotations) Python 3.15a1 3656 (Add TRACE_RECORD instruction, for platforms with switch based interpreter) - + Python 3.15a3 3657 (Optimize bytecode for list/set called on genexp) Python 3.16 will start with 3700 From 1c40a6fdae23cf7fbe62e0cf5fb7651f6a6de59e Mon Sep 17 00:00:00 2001 From: Kumar Aditya Date: Wed, 17 Dec 2025 15:15:11 +0530 Subject: [PATCH 4/5] fix test_dis --- Lib/test/test_dis.py | 26 +++++++++++++++++++++++++- 1 file changed, 25 insertions(+), 1 deletion(-) diff --git a/Lib/test/test_dis.py b/Lib/test/test_dis.py index 3e7477487200d0..902bcdd196ec93 100644 --- a/Lib/test/test_dis.py +++ b/Lib/test/test_dis.py @@ -827,7 +827,14 @@ def foo(x): %4d RESUME 0 -%4d LOAD_GLOBAL 1 (list + NULL) +%4d LOAD_GLOBAL 0 (list) + COPY 1 + LOAD_COMMON_CONSTANT 5 (list) + IS_OP 0 (is) + POP_JUMP_IF_FALSE 22 (to L3) + NOT_TAKEN + POP_TOP + BUILD_LIST 0 LOAD_FAST_BORROW 0 (x) BUILD_TUPLE 1 LOAD_CONST %d ( at 0x..., file "%s", line %d>) @@ -835,6 +842,21 @@ def foo(x): SET_FUNCTION_ATTRIBUTE 8 (closure) LOAD_DEREF 1 (y) CALL 0 + PUSH_NULL + L1: FOR_ITER 3 (to L2) + LIST_APPEND 3 + JUMP_BACKWARD 5 (to L1) + L2: END_FOR + POP_ITER + RETURN_VALUE + L3: PUSH_NULL + LOAD_FAST_BORROW 0 (x) + BUILD_TUPLE 1 + LOAD_CONST 1 ( at 0x..., file "%s", line %d>) + MAKE_FUNCTION + SET_FUNCTION_ATTRIBUTE 8 (closure) + LOAD_DEREF 1 (y) + CALL 0 CALL 1 RETURN_VALUE """ % (dis_nested_0, @@ -845,6 +867,8 @@ def foo(x): 1 if __debug__ else 0, __file__, _h.__code__.co_firstlineno + 3, + __file__, + _h.__code__.co_firstlineno + 3, ) dis_nested_2 = """%s From 5ae3557ec21aff9753ba4851b42cbd043680c23a Mon Sep 17 00:00:00 2001 From: "blurb-it[bot]" <43283697+blurb-it[bot]@users.noreply.github.com> Date: Wed, 17 Dec 2025 10:12:16 +0000 Subject: [PATCH 5/5] =?UTF-8?q?=F0=9F=93=9C=F0=9F=A4=96=20Added=20by=20blu?= =?UTF-8?q?rb=5Fit.?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../2025-12-17-10-12-09.gh-issue-142863.ZW2ZF8.rst | 1 + 1 file changed, 1 insertion(+) create mode 100644 Misc/NEWS.d/next/Core_and_Builtins/2025-12-17-10-12-09.gh-issue-142863.ZW2ZF8.rst diff --git a/Misc/NEWS.d/next/Core_and_Builtins/2025-12-17-10-12-09.gh-issue-142863.ZW2ZF8.rst b/Misc/NEWS.d/next/Core_and_Builtins/2025-12-17-10-12-09.gh-issue-142863.ZW2ZF8.rst new file mode 100644 index 00000000000000..90c8f32b54156f --- /dev/null +++ b/Misc/NEWS.d/next/Core_and_Builtins/2025-12-17-10-12-09.gh-issue-142863.ZW2ZF8.rst @@ -0,0 +1 @@ +Generate optimized bytecode when calling :class:`list` or :class:`set` with generator expression.