diff --git a/Lib/test/test_opcache.py b/Lib/test/test_opcache.py index 2defe74892786d..5509f2f319217c 100644 --- a/Lib/test/test_opcache.py +++ b/Lib/test/test_opcache.py @@ -1348,6 +1348,21 @@ def binary_op_add_extend(): self.assert_specialized(binary_op_add_extend, "BINARY_OP_EXTEND") self.assert_no_opcode(binary_op_add_extend, "BINARY_OP") + def binary_op_add_extend_sequences(): + l1 = [1, 2] + l2 = [None] + t1 = (1, 2) + t2 = (None,) + for _ in range(100): + list_sum = l1 + l2 + self.assertEqual(list_sum, [1, 2, None]) + tuple_sum = t1 + t2 + self.assertEqual(tuple_sum, (1, 2, None)) + + binary_op_add_extend_sequences() + self.assert_specialized(binary_op_add_extend_sequences, "BINARY_OP_EXTEND") + self.assert_no_opcode(binary_op_add_extend_sequences, "BINARY_OP") + def binary_op_zero_division(): def compactlong_lhs(arg): 42 / arg diff --git a/Misc/NEWS.d/next/Core_and_Builtins/2025-01-17-19-48-28.gh-issue-100239.7pbTEA.rst b/Misc/NEWS.d/next/Core_and_Builtins/2025-01-17-19-48-28.gh-issue-100239.7pbTEA.rst new file mode 100644 index 00000000000000..c62497c213507a --- /dev/null +++ b/Misc/NEWS.d/next/Core_and_Builtins/2025-01-17-19-48-28.gh-issue-100239.7pbTEA.rst @@ -0,0 +1 @@ +Specialize ``BINARY_OP`` for concatenation of lists and tuples. diff --git a/Objects/listobject.c b/Objects/listobject.c index f4a269e4d7b284..ec8fa271511ca7 100644 --- a/Objects/listobject.c +++ b/Objects/listobject.c @@ -734,7 +734,7 @@ list_concat_lock_held(PyListObject *a, PyListObject *b) return (PyObject *)np; } -static PyObject * +PyObject * list_concat(PyObject *aa, PyObject *bb) { if (!PyList_Check(bb)) { diff --git a/Objects/tupleobject.c b/Objects/tupleobject.c index 60af9e40e3fe83..d63be9a634fc1b 100644 --- a/Objects/tupleobject.c +++ b/Objects/tupleobject.c @@ -456,7 +456,7 @@ PyTuple_GetSlice(PyObject *op, Py_ssize_t i, Py_ssize_t j) return tuple_slice((PyTupleObject *)op, i, j); } -static PyObject * +PyObject * tuple_concat(PyObject *aa, PyObject *bb) { PyTupleObject *a = _PyTuple_CAST(aa); diff --git a/Python/specialize.c b/Python/specialize.c index abb130d73eeebd..6bc25b80f96644 100644 --- a/Python/specialize.c +++ b/Python/specialize.c @@ -2430,6 +2430,46 @@ binary_op_fail_kind(int oparg, PyObject *lhs, PyObject *rhs) /** Binary Op Specialization Extensions */ +/* tuple-tuple*/ + +static int +tuple_tuple_guard(PyObject *lhs, PyObject *rhs) +{ + return ( PyTuple_CheckExact(lhs) && PyTuple_CheckExact(rhs) ); +} + +extern PyObject * tuple_concat(PyObject *aa, PyObject *bb); + +static PyObject * \ +tuple_tuple_add(PyObject *lhs, PyObject *rhs) \ +{ + return tuple_concat(lhs, rhs); +} + +static _PyBinaryOpSpecializationDescr tuple_tuple_specs[NB_OPARG_LAST+1] = { + [NB_ADD] = {tuple_tuple_guard, tuple_tuple_add}, +}; + +/* list-list*/ + +static int +list_list_guard(PyObject *lhs, PyObject *rhs) +{ + return ( PyList_CheckExact(lhs) && PyList_CheckExact(rhs) ); +} + +extern PyObject * list_concat(PyObject *aa, PyObject *bb); + +static PyObject * \ +list_list_add(PyObject *lhs, PyObject *rhs) \ +{ + return list_concat(lhs, rhs); +} + +static _PyBinaryOpSpecializationDescr list_list_specs[NB_OPARG_LAST+1] = { + [NB_ADD] = {list_list_guard, list_list_add}, +}; + /* long-long */ static inline int @@ -2566,6 +2606,8 @@ binary_op_extended_specialization(PyObject *lhs, PyObject *rhs, int oparg, LOOKUP_SPEC(compactlong_float_specs, oparg); LOOKUP_SPEC(float_compactlong_specs, oparg); LOOKUP_SPEC(compactlongs_specs, oparg); + LOOKUP_SPEC(list_list_specs, oparg); + LOOKUP_SPEC(tuple_tuple_specs, oparg); #undef LOOKUP_SPEC return 0; } diff --git a/Tools/c-analyzer/cpython/ignored.tsv b/Tools/c-analyzer/cpython/ignored.tsv index be3ded9f07ef8a..f48a1379e932ce 100644 --- a/Tools/c-analyzer/cpython/ignored.tsv +++ b/Tools/c-analyzer/cpython/ignored.tsv @@ -384,6 +384,8 @@ Python/specialize.c - cache_requirements - Python/specialize.c - compactlongs_specs - Python/specialize.c - float_compactlong_specs - Python/specialize.c - compactlong_float_specs - +Python/specialize.c - list_list_specs - +Python/specialize.c - tuple_tuple_specs - Python/stdlib_module_names.h - _Py_stdlib_module_names - Python/sysmodule.c - perf_map_state - Python/sysmodule.c - _PySys_ImplCacheTag -