gh-144569: Avoid creating temporary objects in BINARY_SLICE for list, tuple, and unicode (GH-144590)

* Scalar replacement of BINARY_SLICE for list, tuple, and unicode
This commit is contained in:
Hai Zhu 2026-03-03 01:02:38 +08:00 committed by GitHub
parent 1cf5abedeb
commit 107863ee17
No known key found for this signature in database
GPG key ID: B5690EEEBB952194
13 changed files with 256 additions and 77 deletions

View file

@ -866,19 +866,30 @@ dummy_func(
}
op(_BINARY_SLICE, (container, start, stop -- res)) {
PyObject *slice = _PyBuildSlice_ConsumeRefs(PyStackRef_AsPyObjectSteal(start),
PyStackRef_AsPyObjectSteal(stop));
PyObject *container_o = PyStackRef_AsPyObjectBorrow(container);
PyObject *start_o = PyStackRef_AsPyObjectBorrow(start);
PyObject *stop_o = PyStackRef_AsPyObjectBorrow(stop);
PyObject *res_o;
// Can't use ERROR_IF() here, because we haven't
// DECREF'ed container yet, and we still own slice.
if (slice == NULL) {
res_o = NULL;
if (PyList_CheckExact(container_o)) {
res_o = _PyList_BinarySlice(container_o, start_o, stop_o);
}
else if (PyTuple_CheckExact(container_o)) {
res_o = _PyTuple_BinarySlice(container_o, start_o, stop_o);
}
else if (PyUnicode_CheckExact(container_o)) {
res_o = _PyUnicode_BinarySlice(container_o, start_o, stop_o);
}
else {
res_o = PyObject_GetItem(PyStackRef_AsPyObjectBorrow(container), slice);
Py_DECREF(slice);
PyObject *slice = PySlice_New(start_o, stop_o, NULL);
if (slice == NULL) {
res_o = NULL;
}
else {
res_o = PyObject_GetItem(container_o, slice);
Py_DECREF(slice);
}
}
PyStackRef_CLOSE(container);
DECREF_INPUTS();
ERROR_IF(res_o == NULL);
res = PyStackRef_FromPyObjectSteal(res_o);
}

View file

@ -1,6 +1,7 @@
/* Execute compiled code */
#include "ceval.h"
#include "pycore_long.h"
int
Py_GetRecursionLimit(void)
@ -2883,23 +2884,10 @@ PyEval_GetFuncDesc(PyObject *func)
int
_PyEval_SliceIndex(PyObject *v, Py_ssize_t *pi)
{
PyThreadState *tstate = _PyThreadState_GET();
if (!Py_IsNone(v)) {
Py_ssize_t x;
if (_PyIndex_Check(v)) {
x = PyNumber_AsSsize_t(v, NULL);
if (x == -1 && _PyErr_Occurred(tstate))
return 0;
}
else {
_PyErr_SetString(tstate, PyExc_TypeError,
"slice indices must be integers or "
"None or have an __index__ method");
return 0;
}
*pi = x;
if (Py_IsNone(v)) {
return 1;
}
return 1;
return _PyEval_SliceIndexNotNone(v, pi);
}
int
@ -2907,6 +2895,10 @@ _PyEval_SliceIndexNotNone(PyObject *v, Py_ssize_t *pi)
{
PyThreadState *tstate = _PyThreadState_GET();
Py_ssize_t x;
if (PyLong_CheckExact(v) && _PyLong_IsCompact((PyLongObject *)v)) {
*pi = _PyLong_CompactValue((PyLongObject *)v);
return 1;
}
if (_PyIndex_Check(v)) {
x = PyNumber_AsSsize_t(v, NULL);
if (x == -1 && _PyErr_Occurred(tstate))
@ -2922,6 +2914,26 @@ _PyEval_SliceIndexNotNone(PyObject *v, Py_ssize_t *pi)
return 1;
}
int
_PyEval_UnpackIndices(PyObject *start, PyObject *stop,
Py_ssize_t len,
Py_ssize_t *istart, Py_ssize_t *istop)
{
if (len < 0) {
return 0;
}
*istart = 0;
*istop = PY_SSIZE_T_MAX;
if (!_PyEval_SliceIndex(start, istart)) {
return 0;
}
if (!_PyEval_SliceIndex(stop, istop)) {
return 0;
}
PySlice_AdjustIndices(len, istart, istop, 1);
return 1;
}
PyObject *
_PyEval_ImportName(PyThreadState *tstate, PyObject *builtins,
PyObject *globals, PyObject *locals, PyObject *name,

View file

@ -5198,33 +5198,77 @@
stop = _stack_item_2;
start = _stack_item_1;
container = _stack_item_0;
stack_pointer[0] = container;
stack_pointer[1] = start;
stack_pointer[2] = stop;
stack_pointer += 3;
ASSERT_WITHIN_STACK_BOUNDS(__FILE__, __LINE__);
_PyFrame_SetStackPointer(frame, stack_pointer);
PyObject *slice = _PyBuildSlice_ConsumeRefs(PyStackRef_AsPyObjectSteal(start),
PyStackRef_AsPyObjectSteal(stop));
stack_pointer = _PyFrame_GetStackPointer(frame);
PyObject *container_o = PyStackRef_AsPyObjectBorrow(container);
PyObject *start_o = PyStackRef_AsPyObjectBorrow(start);
PyObject *stop_o = PyStackRef_AsPyObjectBorrow(stop);
PyObject *res_o;
if (slice == NULL) {
res_o = NULL;
}
else {
stack_pointer += -2;
if (PyList_CheckExact(container_o)) {
stack_pointer[0] = container;
stack_pointer[1] = start;
stack_pointer[2] = stop;
stack_pointer += 3;
ASSERT_WITHIN_STACK_BOUNDS(__FILE__, __LINE__);
_PyFrame_SetStackPointer(frame, stack_pointer);
res_o = PyObject_GetItem(PyStackRef_AsPyObjectBorrow(container), slice);
Py_DECREF(slice);
res_o = _PyList_BinarySlice(container_o, start_o, stop_o);
stack_pointer = _PyFrame_GetStackPointer(frame);
stack_pointer += 2;
}
else if (PyTuple_CheckExact(container_o)) {
stack_pointer[0] = container;
stack_pointer[1] = start;
stack_pointer[2] = stop;
stack_pointer += 3;
ASSERT_WITHIN_STACK_BOUNDS(__FILE__, __LINE__);
_PyFrame_SetStackPointer(frame, stack_pointer);
res_o = _PyTuple_BinarySlice(container_o, start_o, stop_o);
stack_pointer = _PyFrame_GetStackPointer(frame);
}
else if (PyUnicode_CheckExact(container_o)) {
stack_pointer[0] = container;
stack_pointer[1] = start;
stack_pointer[2] = stop;
stack_pointer += 3;
ASSERT_WITHIN_STACK_BOUNDS(__FILE__, __LINE__);
_PyFrame_SetStackPointer(frame, stack_pointer);
res_o = _PyUnicode_BinarySlice(container_o, start_o, stop_o);
stack_pointer = _PyFrame_GetStackPointer(frame);
}
else {
PyObject *slice = PySlice_New(start_o, stop_o, NULL);
if (slice == NULL) {
res_o = NULL;
}
else {
stack_pointer[0] = container;
stack_pointer[1] = start;
stack_pointer[2] = stop;
stack_pointer += 3;
ASSERT_WITHIN_STACK_BOUNDS(__FILE__, __LINE__);
_PyFrame_SetStackPointer(frame, stack_pointer);
res_o = PyObject_GetItem(container_o, slice);
Py_DECREF(slice);
stack_pointer = _PyFrame_GetStackPointer(frame);
stack_pointer += -3;
}
stack_pointer += 3;
}
_PyFrame_SetStackPointer(frame, stack_pointer);
_PyStackRef tmp = stop;
stop = PyStackRef_NULL;
stack_pointer[-3] = container;
stack_pointer[-2] = start;
stack_pointer[-1] = stop;
PyStackRef_CLOSE(tmp);
tmp = start;
start = PyStackRef_NULL;
stack_pointer[-2] = start;
PyStackRef_CLOSE(tmp);
tmp = container;
container = PyStackRef_NULL;
stack_pointer[-3] = container;
PyStackRef_CLOSE(tmp);
stack_pointer = _PyFrame_GetStackPointer(frame);
stack_pointer += -3;
ASSERT_WITHIN_STACK_BOUNDS(__FILE__, __LINE__);
_PyFrame_SetStackPointer(frame, stack_pointer);
PyStackRef_CLOSE(container);
stack_pointer = _PyFrame_GetStackPointer(frame);
if (res_o == NULL) {
SET_CURRENT_CACHED_VALUES(0);
JUMP_TO_ERROR();

View file

@ -1396,28 +1396,53 @@
stop = stack_pointer[-1];
start = stack_pointer[-2];
container = stack_pointer[-3];
_PyFrame_SetStackPointer(frame, stack_pointer);
PyObject *slice = _PyBuildSlice_ConsumeRefs(PyStackRef_AsPyObjectSteal(start),
PyStackRef_AsPyObjectSteal(stop));
stack_pointer = _PyFrame_GetStackPointer(frame);
PyObject *container_o = PyStackRef_AsPyObjectBorrow(container);
PyObject *start_o = PyStackRef_AsPyObjectBorrow(start);
PyObject *stop_o = PyStackRef_AsPyObjectBorrow(stop);
PyObject *res_o;
if (slice == NULL) {
res_o = NULL;
if (PyList_CheckExact(container_o)) {
_PyFrame_SetStackPointer(frame, stack_pointer);
res_o = _PyList_BinarySlice(container_o, start_o, stop_o);
stack_pointer = _PyFrame_GetStackPointer(frame);
}
else if (PyTuple_CheckExact(container_o)) {
_PyFrame_SetStackPointer(frame, stack_pointer);
res_o = _PyTuple_BinarySlice(container_o, start_o, stop_o);
stack_pointer = _PyFrame_GetStackPointer(frame);
}
else if (PyUnicode_CheckExact(container_o)) {
_PyFrame_SetStackPointer(frame, stack_pointer);
res_o = _PyUnicode_BinarySlice(container_o, start_o, stop_o);
stack_pointer = _PyFrame_GetStackPointer(frame);
}
else {
stack_pointer += -2;
ASSERT_WITHIN_STACK_BOUNDS(__FILE__, __LINE__);
_PyFrame_SetStackPointer(frame, stack_pointer);
res_o = PyObject_GetItem(PyStackRef_AsPyObjectBorrow(container), slice);
Py_DECREF(slice);
stack_pointer = _PyFrame_GetStackPointer(frame);
stack_pointer += 2;
PyObject *slice = PySlice_New(start_o, stop_o, NULL);
if (slice == NULL) {
res_o = NULL;
}
else {
_PyFrame_SetStackPointer(frame, stack_pointer);
res_o = PyObject_GetItem(container_o, slice);
Py_DECREF(slice);
stack_pointer = _PyFrame_GetStackPointer(frame);
}
}
_PyFrame_SetStackPointer(frame, stack_pointer);
_PyStackRef tmp = stop;
stop = PyStackRef_NULL;
stack_pointer[-1] = stop;
PyStackRef_CLOSE(tmp);
tmp = start;
start = PyStackRef_NULL;
stack_pointer[-2] = start;
PyStackRef_CLOSE(tmp);
tmp = container;
container = PyStackRef_NULL;
stack_pointer[-3] = container;
PyStackRef_CLOSE(tmp);
stack_pointer = _PyFrame_GetStackPointer(frame);
stack_pointer += -3;
ASSERT_WITHIN_STACK_BOUNDS(__FILE__, __LINE__);
_PyFrame_SetStackPointer(frame, stack_pointer);
PyStackRef_CLOSE(container);
stack_pointer = _PyFrame_GetStackPointer(frame);
if (res_o == NULL) {
JUMP_TO_LABEL(error);
}