From 569002d37e080e30a8b0b9ffa55e01909df63a6f Mon Sep 17 00:00:00 2001 From: Pieter Eendebak Date: Thu, 19 Feb 2026 23:42:38 +0100 Subject: [PATCH 1/5] Avoid reference counts on pyslice_fromindices --- Objects/sliceobject.c | 4 +--- 1 file changed, 1 insertion(+), 3 deletions(-) diff --git a/Objects/sliceobject.c b/Objects/sliceobject.c index 95f10815687757..80546db467784e 100644 --- a/Objects/sliceobject.c +++ b/Objects/sliceobject.c @@ -177,9 +177,7 @@ _PySlice_FromIndices(Py_ssize_t istart, Py_ssize_t istop) return NULL; } - slice = PySlice_New(start, end, NULL); - Py_DECREF(start); - Py_DECREF(end); + slice = _PyBuildSlice_ConsumeRefs(start, end); return slice; } From 66c1209f83a5a203b3210f313381f2d55663b029 Mon Sep 17 00:00:00 2001 From: Pieter Eendebak Date: Thu, 19 Feb 2026 23:54:21 +0100 Subject: [PATCH 2/5] avoid incref on step argument --- Objects/sliceobject.c | 11 ++++++----- 1 file changed, 6 insertions(+), 5 deletions(-) diff --git a/Objects/sliceobject.c b/Objects/sliceobject.c index 80546db467784e..e37977045433c2 100644 --- a/Objects/sliceobject.c +++ b/Objects/sliceobject.c @@ -118,7 +118,7 @@ PyObject _Py_EllipsisObject = _PyObject_HEAD_INIT(&PyEllipsis_Type); */ static PySliceObject * -_PyBuildSlice_Consume2(PyObject *start, PyObject *stop, PyObject *step) +_PyBuildSlice_Consume3(PyObject *start, PyObject *stop, PyObject *step) { assert(start != NULL && stop != NULL && step != NULL); PySliceObject *obj = _Py_FREELIST_POP(PySliceObject, slices); @@ -131,13 +131,14 @@ _PyBuildSlice_Consume2(PyObject *start, PyObject *stop, PyObject *step) obj->start = start; obj->stop = stop; - obj->step = Py_NewRef(step); + obj->step = step; _PyObject_GC_TRACK(obj); return obj; error: Py_DECREF(start); Py_DECREF(stop); + Py_DECREF(step); return NULL; } @@ -153,15 +154,15 @@ PySlice_New(PyObject *start, PyObject *stop, PyObject *step) if (stop == NULL) { stop = Py_None; } - return (PyObject *)_PyBuildSlice_Consume2(Py_NewRef(start), - Py_NewRef(stop), step); + return (PyObject *)_PyBuildSlice_Consume3(Py_NewRef(start), + Py_NewRef(stop), Py_NewRef(step)); } PyObject * _PyBuildSlice_ConsumeRefs(PyObject *start, PyObject *stop) { assert(start != NULL && stop != NULL); - return (PyObject *)_PyBuildSlice_Consume2(start, stop, Py_None); + return (PyObject *)_PyBuildSlice_Consume3(start, stop, Py_None); } PyObject * From d7b03678e123673ec02c1dae777104216d3aee6d Mon Sep 17 00:00:00 2001 From: "blurb-it[bot]" <43283697+blurb-it[bot]@users.noreply.github.com> Date: Tue, 24 Feb 2026 20:07:50 +0000 Subject: [PATCH 3/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 --- .../next/C_API/2026-02-24-20-07-41.gh-issue-145192.Td5zue.rst | 1 + 1 file changed, 1 insertion(+) create mode 100644 Misc/NEWS.d/next/C_API/2026-02-24-20-07-41.gh-issue-145192.Td5zue.rst diff --git a/Misc/NEWS.d/next/C_API/2026-02-24-20-07-41.gh-issue-145192.Td5zue.rst b/Misc/NEWS.d/next/C_API/2026-02-24-20-07-41.gh-issue-145192.Td5zue.rst new file mode 100644 index 00000000000000..12f2b0bed7f1e2 --- /dev/null +++ b/Misc/NEWS.d/next/C_API/2026-02-24-20-07-41.gh-issue-145192.Td5zue.rst @@ -0,0 +1 @@ +Improve performance of :c:func:`PySequence_GetSlice`. From bdd742c43bc5c3ddbfad2494be9a4ee6e0cdee43 Mon Sep 17 00:00:00 2001 From: Pieter Eendebak Date: Thu, 26 Feb 2026 13:08:05 +0100 Subject: [PATCH 4/5] drop news entry --- .../next/C_API/2026-02-24-20-07-41.gh-issue-145192.Td5zue.rst | 1 - 1 file changed, 1 deletion(-) delete mode 100644 Misc/NEWS.d/next/C_API/2026-02-24-20-07-41.gh-issue-145192.Td5zue.rst diff --git a/Misc/NEWS.d/next/C_API/2026-02-24-20-07-41.gh-issue-145192.Td5zue.rst b/Misc/NEWS.d/next/C_API/2026-02-24-20-07-41.gh-issue-145192.Td5zue.rst deleted file mode 100644 index 12f2b0bed7f1e2..00000000000000 --- a/Misc/NEWS.d/next/C_API/2026-02-24-20-07-41.gh-issue-145192.Td5zue.rst +++ /dev/null @@ -1 +0,0 @@ -Improve performance of :c:func:`PySequence_GetSlice`. From 38c9de5cb3cb6e01e62bcbda23666d8faee10413 Mon Sep 17 00:00:00 2001 From: Pieter Eendebak Date: Thu, 26 Feb 2026 13:34:46 +0100 Subject: [PATCH 5/5] review comments --- Include/internal/pycore_sliceobject.h | 2 +- Modules/_testinternalcapi/test_cases.c.h | 6 ++++-- Objects/sliceobject.c | 17 +++++------------ Python/bytecodes.c | 6 ++++-- Python/executor_cases.c.h | 6 ++++-- Python/generated_cases.c.h | 6 ++++-- 6 files changed, 22 insertions(+), 21 deletions(-) diff --git a/Include/internal/pycore_sliceobject.h b/Include/internal/pycore_sliceobject.h index ba8b1f1cb27dee..b6c821764886c3 100644 --- a/Include/internal/pycore_sliceobject.h +++ b/Include/internal/pycore_sliceobject.h @@ -12,7 +12,7 @@ extern "C" { /* runtime lifecycle */ PyAPI_FUNC(PyObject *) -_PyBuildSlice_ConsumeRefs(PyObject *start, PyObject *stop); +_PyBuildSlice_ConsumeRefs(PyObject *start, PyObject *stop, PyObject *step); #ifdef __cplusplus } diff --git a/Modules/_testinternalcapi/test_cases.c.h b/Modules/_testinternalcapi/test_cases.c.h index 395c429f7ef3db..b08fc17233f38f 100644 --- a/Modules/_testinternalcapi/test_cases.c.h +++ b/Modules/_testinternalcapi/test_cases.c.h @@ -1398,7 +1398,8 @@ container = stack_pointer[-3]; _PyFrame_SetStackPointer(frame, stack_pointer); PyObject *slice = _PyBuildSlice_ConsumeRefs(PyStackRef_AsPyObjectSteal(start), - PyStackRef_AsPyObjectSteal(stop)); + PyStackRef_AsPyObjectSteal(stop), + Py_None); stack_pointer = _PyFrame_GetStackPointer(frame); PyObject *res_o; if (slice == NULL) { @@ -11370,7 +11371,8 @@ v = stack_pointer[-4]; _PyFrame_SetStackPointer(frame, stack_pointer); PyObject *slice = _PyBuildSlice_ConsumeRefs(PyStackRef_AsPyObjectSteal(start), - PyStackRef_AsPyObjectSteal(stop)); + PyStackRef_AsPyObjectSteal(stop), + Py_None); stack_pointer = _PyFrame_GetStackPointer(frame); int err; if (slice == NULL) { diff --git a/Objects/sliceobject.c b/Objects/sliceobject.c index e37977045433c2..96ff3118dc4405 100644 --- a/Objects/sliceobject.c +++ b/Objects/sliceobject.c @@ -117,8 +117,8 @@ PyObject _Py_EllipsisObject = _PyObject_HEAD_INIT(&PyEllipsis_Type); index is present. */ -static PySliceObject * -_PyBuildSlice_Consume3(PyObject *start, PyObject *stop, PyObject *step) +PyObject * +_PyBuildSlice_ConsumeRefs(PyObject *start, PyObject *stop, PyObject *step) { assert(start != NULL && stop != NULL && step != NULL); PySliceObject *obj = _Py_FREELIST_POP(PySliceObject, slices); @@ -134,7 +134,7 @@ _PyBuildSlice_Consume3(PyObject *start, PyObject *stop, PyObject *step) obj->step = step; _PyObject_GC_TRACK(obj); - return obj; + return (PyObject *)obj; error: Py_DECREF(start); Py_DECREF(stop); @@ -154,17 +154,10 @@ PySlice_New(PyObject *start, PyObject *stop, PyObject *step) if (stop == NULL) { stop = Py_None; } - return (PyObject *)_PyBuildSlice_Consume3(Py_NewRef(start), + return _PyBuildSlice_ConsumeRefs(Py_NewRef(start), Py_NewRef(stop), Py_NewRef(step)); } -PyObject * -_PyBuildSlice_ConsumeRefs(PyObject *start, PyObject *stop) -{ - assert(start != NULL && stop != NULL); - return (PyObject *)_PyBuildSlice_Consume3(start, stop, Py_None); -} - PyObject * _PySlice_FromIndices(Py_ssize_t istart, Py_ssize_t istop) { @@ -178,7 +171,7 @@ _PySlice_FromIndices(Py_ssize_t istart, Py_ssize_t istop) return NULL; } - slice = _PyBuildSlice_ConsumeRefs(start, end); + slice = _PyBuildSlice_ConsumeRefs(start, end, Py_None); return slice; } diff --git a/Python/bytecodes.c b/Python/bytecodes.c index 36af61412b7417..2ee1040092dae4 100644 --- a/Python/bytecodes.c +++ b/Python/bytecodes.c @@ -867,7 +867,8 @@ dummy_func( op(_BINARY_SLICE, (container, start, stop -- res)) { PyObject *slice = _PyBuildSlice_ConsumeRefs(PyStackRef_AsPyObjectSteal(start), - PyStackRef_AsPyObjectSteal(stop)); + PyStackRef_AsPyObjectSteal(stop), + Py_None); PyObject *res_o; // Can't use ERROR_IF() here, because we haven't // DECREF'ed container yet, and we still own slice. @@ -894,7 +895,8 @@ dummy_func( op(_STORE_SLICE, (v, container, start, stop -- )) { PyObject *slice = _PyBuildSlice_ConsumeRefs(PyStackRef_AsPyObjectSteal(start), - PyStackRef_AsPyObjectSteal(stop)); + PyStackRef_AsPyObjectSteal(stop), + Py_None); int err; if (slice == NULL) { err = 1; diff --git a/Python/executor_cases.c.h b/Python/executor_cases.c.h index 4a67ede8a02265..50f7a8233c1b55 100644 --- a/Python/executor_cases.c.h +++ b/Python/executor_cases.c.h @@ -5205,7 +5205,8 @@ ASSERT_WITHIN_STACK_BOUNDS(__FILE__, __LINE__); _PyFrame_SetStackPointer(frame, stack_pointer); PyObject *slice = _PyBuildSlice_ConsumeRefs(PyStackRef_AsPyObjectSteal(start), - PyStackRef_AsPyObjectSteal(stop)); + PyStackRef_AsPyObjectSteal(stop), + Py_None); stack_pointer = _PyFrame_GetStackPointer(frame); PyObject *res_o; if (slice == NULL) { @@ -5259,7 +5260,8 @@ ASSERT_WITHIN_STACK_BOUNDS(__FILE__, __LINE__); _PyFrame_SetStackPointer(frame, stack_pointer); PyObject *slice = _PyBuildSlice_ConsumeRefs(PyStackRef_AsPyObjectSteal(start), - PyStackRef_AsPyObjectSteal(stop)); + PyStackRef_AsPyObjectSteal(stop), + Py_None); stack_pointer = _PyFrame_GetStackPointer(frame); int err; if (slice == NULL) { diff --git a/Python/generated_cases.c.h b/Python/generated_cases.c.h index 12362943465e3d..1db84b7d90308d 100644 --- a/Python/generated_cases.c.h +++ b/Python/generated_cases.c.h @@ -1398,7 +1398,8 @@ container = stack_pointer[-3]; _PyFrame_SetStackPointer(frame, stack_pointer); PyObject *slice = _PyBuildSlice_ConsumeRefs(PyStackRef_AsPyObjectSteal(start), - PyStackRef_AsPyObjectSteal(stop)); + PyStackRef_AsPyObjectSteal(stop), + Py_None); stack_pointer = _PyFrame_GetStackPointer(frame); PyObject *res_o; if (slice == NULL) { @@ -11367,7 +11368,8 @@ v = stack_pointer[-4]; _PyFrame_SetStackPointer(frame, stack_pointer); PyObject *slice = _PyBuildSlice_ConsumeRefs(PyStackRef_AsPyObjectSteal(start), - PyStackRef_AsPyObjectSteal(stop)); + PyStackRef_AsPyObjectSteal(stop), + Py_None); stack_pointer = _PyFrame_GetStackPointer(frame); int err; if (slice == NULL) {