PyAPI_FUNC(int) _PyEval_SliceIndex(PyObject *, Py_ssize_t *);
PyAPI_FUNC(int) _PyEval_SliceIndexNotNone(PyObject *, Py_ssize_t *);
+PyAPI_FUNC(int) _PyEval_UnpackIndices(PyObject *, PyObject *,
+ Py_ssize_t,
+ Py_ssize_t *, Py_ssize_t *);
// Trampoline API
PyAPI_FUNC(PyObject*) _PyList_Extend(PyListObject *, PyObject *);
PyAPI_FUNC(PyObject) *_PyList_SliceSubscript(PyObject*, PyObject*);
+PyAPI_FUNC(PyObject *) _PyList_BinarySlice(PyObject *, PyObject *, PyObject *);
extern void _PyList_DebugMallocStats(FILE *out);
// _PyList_GetItemRef should be used only when the object is known as a list
// because it doesn't raise TypeError when the object is not a list, whereas PyList_GetItemRef does.
PyAPI_FUNC(PyObject *)_PyTuple_FromStackRefStealOnSuccess(const union _PyStackRef *, Py_ssize_t);
PyAPI_FUNC(PyObject *)_PyTuple_FromArraySteal(PyObject *const *, Py_ssize_t);
+PyAPI_FUNC(PyObject *) _PyTuple_BinarySlice(PyObject *, PyObject *, PyObject *);
typedef struct {
PyObject_HEAD
PyObject *unicode,
Py_ssize_t length);
extern PyObject* _PyUnicode_GetEmpty(void);
+PyAPI_FUNC(PyObject*) _PyUnicode_BinarySlice(PyObject *, PyObject *, PyObject *);
/* Generic helper macro to convert characters of different types.
--- /dev/null
+Optimize ``BINARY_SLICE`` for list, tuple, and unicode by avoiding temporary ``slice`` object creation.
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 {
- stack_pointer += -2;
- ASSERT_WITHIN_STACK_BOUNDS(__FILE__, __LINE__);
+ else if (PyTuple_CheckExact(container_o)) {
_PyFrame_SetStackPointer(frame, stack_pointer);
- res_o = PyObject_GetItem(PyStackRef_AsPyObjectBorrow(container), slice);
- Py_DECREF(slice);
+ res_o = _PyTuple_BinarySlice(container_o, start_o, stop_o);
stack_pointer = _PyFrame_GetStackPointer(frame);
- stack_pointer += 2;
}
- stack_pointer += -3;
- ASSERT_WITHIN_STACK_BOUNDS(__FILE__, __LINE__);
+ 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 {
+ 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_CLOSE(container);
+ _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__);
if (res_o == NULL) {
JUMP_TO_LABEL(error);
}
return (PyObject *)np;
}
+PyObject *
+_PyList_BinarySlice(PyObject *container, PyObject *start, PyObject *stop)
+{
+ assert(PyList_CheckExact(container));
+ Py_ssize_t istart = 0;
+ Py_ssize_t istop = PY_SSIZE_T_MAX;
+ /* Unpack the index values before acquiring the lock, since
+ * _PyEval_SliceIndex may call __index__ which could execute
+ * arbitrary Python code. */
+ if (!_PyEval_SliceIndex(start, &istart)) {
+ return NULL;
+ }
+ if (!_PyEval_SliceIndex(stop, &istop)) {
+ return NULL;
+ }
+ PyObject *ret;
+ Py_BEGIN_CRITICAL_SECTION(container);
+ Py_ssize_t len = Py_SIZE(container);
+ PySlice_AdjustIndices(len, &istart, &istop, 1);
+ ret = list_slice_lock_held((PyListObject *)container, istart, istop);
+ Py_END_CRITICAL_SECTION();
+ return ret;
+}
+
PyObject *
PyList_GetSlice(PyObject *a, Py_ssize_t ilow, Py_ssize_t ihigh)
{
return PyTuple_FromArray(a->ob_item + ilow, ihigh - ilow);
}
+PyObject *
+_PyTuple_BinarySlice(PyObject *container, PyObject *start, PyObject *stop)
+{
+ assert(PyTuple_CheckExact(container));
+ Py_ssize_t len = Py_SIZE(container);
+ Py_ssize_t istart, istop;
+ if (!_PyEval_UnpackIndices(start, stop, len, &istart, &istop)) {
+ return NULL;
+ }
+ if (istart == 0 && istop == len) {
+ return Py_NewRef(container);
+ }
+ if (istop < istart) {
+ istop = istart;
+ }
+ return PyTuple_FromArray(((PyTupleObject *)container)->ob_item + istart,
+ istop - istart);
+}
+
PyObject *
PyTuple_GetSlice(PyObject *op, Py_ssize_t i, Py_ssize_t j)
{
return PyUnicode_Substring(self, i, j);
}
+PyObject*
+_PyUnicode_BinarySlice(PyObject *container, PyObject *start_o, PyObject *stop_o)
+{
+ assert(PyUnicode_CheckExact(container));
+ Py_ssize_t len = PyUnicode_GET_LENGTH(container);
+ Py_ssize_t istart, istop;
+ if (!_PyEval_UnpackIndices(start_o, stop_o, len, &istart, &istop)) {
+ return NULL;
+ }
+ return PyUnicode_Substring(container, istart, istop);
+}
+
PyObject*
PyUnicode_Substring(PyObject *self, Py_ssize_t start, Py_ssize_t end)
{
}
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);
}
/* Execute compiled code */
#include "ceval.h"
+#include "pycore_long.h"
int
Py_GetRecursionLimit(void)
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
{
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))
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,
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;
+ 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 = _PyList_BinarySlice(container_o, start_o, stop_o);
+ stack_pointer = _PyFrame_GetStackPointer(frame);
}
- else {
- 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 = PyObject_GetItem(PyStackRef_AsPyObjectBorrow(container), slice);
- Py_DECREF(slice);
+ res_o = _PyTuple_BinarySlice(container_o, start_o, stop_o);
stack_pointer = _PyFrame_GetStackPointer(frame);
- stack_pointer += 2;
}
- stack_pointer += -3;
- ASSERT_WITHIN_STACK_BOUNDS(__FILE__, __LINE__);
+ 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_CLOSE(container);
+ _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__);
if (res_o == NULL) {
SET_CURRENT_CACHED_VALUES(0);
JUMP_TO_ERROR();
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 {
- stack_pointer += -2;
- ASSERT_WITHIN_STACK_BOUNDS(__FILE__, __LINE__);
+ else if (PyTuple_CheckExact(container_o)) {
_PyFrame_SetStackPointer(frame, stack_pointer);
- res_o = PyObject_GetItem(PyStackRef_AsPyObjectBorrow(container), slice);
- Py_DECREF(slice);
+ res_o = _PyTuple_BinarySlice(container_o, start_o, stop_o);
stack_pointer = _PyFrame_GetStackPointer(frame);
- stack_pointer += 2;
}
- stack_pointer += -3;
- ASSERT_WITHIN_STACK_BOUNDS(__FILE__, __LINE__);
+ 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 {
+ 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_CLOSE(container);
+ _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__);
if (res_o == NULL) {
JUMP_TO_LABEL(error);
}