Skip to content

Commit d68c600

Browse files
committed
reduce function call
1 parent b1fa60f commit d68c600

11 files changed

Lines changed: 144 additions & 112 deletions

File tree

Include/internal/pycore_list.h

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -14,6 +14,7 @@ extern "C" {
1414

1515
PyAPI_FUNC(PyObject*) _PyList_Extend(PyListObject *, PyObject *);
1616
PyAPI_FUNC(PyObject) *_PyList_SliceSubscript(PyObject*, PyObject*);
17+
PyAPI_FUNC(PyObject *) _PyList_BinarySlice(PyObject *, PyObject *, PyObject *);
1718
extern void _PyList_DebugMallocStats(FILE *out);
1819
// _PyList_GetItemRef should be used only when the object is known as a list
1920
// because it doesn't raise TypeError when the object is not a list, whereas PyList_GetItemRef does.

Include/internal/pycore_tuple.h

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -25,6 +25,7 @@ extern PyStatus _PyTuple_InitGlobalObjects(PyInterpreterState *);
2525

2626
PyAPI_FUNC(PyObject *)_PyTuple_FromStackRefStealOnSuccess(const union _PyStackRef *, Py_ssize_t);
2727
PyAPI_FUNC(PyObject *)_PyTuple_FromArraySteal(PyObject *const *, Py_ssize_t);
28+
PyAPI_FUNC(PyObject *) _PyTuple_BinarySlice(PyObject *, PyObject *, PyObject *);
2829

2930
typedef struct {
3031
PyObject_HEAD

Include/internal/pycore_unicodeobject.h

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -32,6 +32,7 @@ extern PyObject* _PyUnicode_ResizeCompact(
3232
PyObject *unicode,
3333
Py_ssize_t length);
3434
extern PyObject* _PyUnicode_GetEmpty(void);
35+
PyAPI_FUNC(PyObject*) _PyUnicode_BinarySlice(PyObject *, PyObject *, PyObject *);
3536

3637

3738
/* Generic helper macro to convert characters of different types.

Modules/_testinternalcapi/test_cases.c.h

Lines changed: 12 additions & 29 deletions
Some generated files are not rendered by default. Learn more about customizing how changed files appear on GitHub.

Objects/listobject.c

Lines changed: 24 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -716,6 +716,30 @@ list_slice_lock_held(PyListObject *a, Py_ssize_t ilow, Py_ssize_t ihigh)
716716
return (PyObject *)np;
717717
}
718718

719+
PyObject *
720+
_PyList_BinarySlice(PyObject *container, PyObject *start, PyObject *stop)
721+
{
722+
assert(PyList_CheckExact(container));
723+
Py_ssize_t istart = 0;
724+
Py_ssize_t istop = PY_SSIZE_T_MAX;
725+
/* Unpack the index values before acquiring the lock, since
726+
* _PyEval_SliceIndex may call __index__ which could execute
727+
* arbitrary Python code. */
728+
if (!_PyEval_SliceIndex(start, &istart)) {
729+
return NULL;
730+
}
731+
if (!_PyEval_SliceIndex(stop, &istop)) {
732+
return NULL;
733+
}
734+
PyObject *ret;
735+
Py_BEGIN_CRITICAL_SECTION(container);
736+
Py_ssize_t len = Py_SIZE(container);
737+
PySlice_AdjustIndices(len, &istart, &istop, 1);
738+
ret = list_slice_lock_held((PyListObject *)container, istart, istop);
739+
Py_END_CRITICAL_SECTION();
740+
return ret;
741+
}
742+
719743
PyObject *
720744
PyList_GetSlice(PyObject *a, Py_ssize_t ilow, Py_ssize_t ihigh)
721745
{

Objects/tupleobject.c

Lines changed: 19 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -472,6 +472,25 @@ tuple_slice(PyTupleObject *a, Py_ssize_t ilow,
472472
return PyTuple_FromArray(a->ob_item + ilow, ihigh - ilow);
473473
}
474474

475+
PyObject *
476+
_PyTuple_BinarySlice(PyObject *container, PyObject *start, PyObject *stop)
477+
{
478+
assert(PyTuple_CheckExact(container));
479+
Py_ssize_t len = Py_SIZE(container);
480+
Py_ssize_t istart, istop;
481+
if (!_PyEval_UnpackIndices(start, stop, len, &istart, &istop)) {
482+
return NULL;
483+
}
484+
if (istart == 0 && istop == len) {
485+
return Py_NewRef(container);
486+
}
487+
if (istop < istart) {
488+
istop = istart;
489+
}
490+
return PyTuple_FromArray(((PyTupleObject *)container)->ob_item + istart,
491+
istop - istart);
492+
}
493+
475494
PyObject *
476495
PyTuple_GetSlice(PyObject *op, Py_ssize_t i, Py_ssize_t j)
477496
{

Objects/unicodeobject.c

Lines changed: 12 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -12312,6 +12312,18 @@ _PyUnicode_XStrip(PyObject *self, int striptype, PyObject *sepobj)
1231212312
return PyUnicode_Substring(self, i, j);
1231312313
}
1231412314

12315+
PyObject*
12316+
_PyUnicode_BinarySlice(PyObject *container, PyObject *start_o, PyObject *stop_o)
12317+
{
12318+
assert(PyUnicode_CheckExact(container));
12319+
Py_ssize_t len = PyUnicode_GET_LENGTH(container);
12320+
Py_ssize_t istart, istop;
12321+
if (!_PyEval_UnpackIndices(start_o, stop_o, len, &istart, &istop)) {
12322+
return NULL;
12323+
}
12324+
return PyUnicode_Substring(container, istart, istop);
12325+
}
12326+
1231512327
PyObject*
1231612328
PyUnicode_Substring(PyObject *self, Py_ssize_t start, Py_ssize_t end)
1231712329
{

Python/bytecodes.c

Lines changed: 8 additions & 23 deletions
Original file line numberDiff line numberDiff line change
@@ -870,29 +870,14 @@ dummy_func(
870870
PyObject *start_o = PyStackRef_AsPyObjectBorrow(start);
871871
PyObject *stop_o = PyStackRef_AsPyObjectBorrow(stop);
872872
PyObject *res_o;
873-
if ((PyList_CheckExact(container_o) ||
874-
PyTuple_CheckExact(container_o) ||
875-
PyUnicode_CheckExact(container_o)) &&
876-
(start_o == Py_None || PyLong_CheckExact(start_o)) &&
877-
(stop_o == Py_None || PyLong_CheckExact(stop_o))) {
878-
Py_ssize_t len = PyUnicode_CheckExact(container_o)
879-
? PyUnicode_GET_LENGTH(container_o)
880-
: Py_SIZE(container_o);
881-
Py_ssize_t istart, istop;
882-
int err = _PyEval_UnpackIndices(start_o, stop_o, len,
883-
&istart, &istop);
884-
if (err == 0) {
885-
res_o = NULL;
886-
}
887-
else if (PyList_CheckExact(container_o)) {
888-
res_o = PyList_GetSlice(container_o, istart, istop);
889-
}
890-
else if (PyTuple_CheckExact(container_o)) {
891-
res_o = PyTuple_GetSlice(container_o, istart, istop);
892-
}
893-
else {
894-
res_o = PyUnicode_Substring(container_o, istart, istop);
895-
}
873+
if (PyList_CheckExact(container_o)) {
874+
res_o = _PyList_BinarySlice(container_o, start_o, stop_o);
875+
}
876+
else if (PyTuple_CheckExact(container_o)) {
877+
res_o = _PyTuple_BinarySlice(container_o, start_o, stop_o);
878+
}
879+
else if (PyUnicode_CheckExact(container_o)) {
880+
res_o = _PyUnicode_BinarySlice(container_o, start_o, stop_o);
896881
}
897882
else {
898883
PyObject *slice = PySlice_New(start_o, stop_o, NULL);

Python/ceval.c

Lines changed: 32 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,7 @@
11
/* Execute compiled code */
22

33
#include "ceval.h"
4+
#include "pycore_long.h"
45

56
int
67
Py_GetRecursionLimit(void)
@@ -2886,7 +2887,22 @@ _PyEval_SliceIndex(PyObject *v, Py_ssize_t *pi)
28862887
PyThreadState *tstate = _PyThreadState_GET();
28872888
if (!Py_IsNone(v)) {
28882889
Py_ssize_t x;
2889-
if (_PyIndex_Check(v)) {
2890+
if (PyLong_CheckExact(v)) {
2891+
// Fast path for compact ints (single digit) -- most slice indices.
2892+
if (_PyLong_IsCompact((PyLongObject *)v)) {
2893+
x = _PyLong_CompactValue((PyLongObject *)v);
2894+
}
2895+
else {
2896+
x = PyLong_AsSsize_t(v);
2897+
if (x == -1 && _PyErr_Occurred(tstate)) {
2898+
assert(_PyErr_ExceptionMatches(tstate, PyExc_OverflowError));
2899+
_PyErr_Clear(tstate);
2900+
x = _PyLong_IsNegative((PyLongObject *)v)
2901+
? PY_SSIZE_T_MIN : PY_SSIZE_T_MAX;
2902+
}
2903+
}
2904+
}
2905+
else if (_PyIndex_Check(v)) {
28902906
x = PyNumber_AsSsize_t(v, NULL);
28912907
if (x == -1 && _PyErr_Occurred(tstate))
28922908
return 0;
@@ -2907,7 +2923,21 @@ _PyEval_SliceIndexNotNone(PyObject *v, Py_ssize_t *pi)
29072923
{
29082924
PyThreadState *tstate = _PyThreadState_GET();
29092925
Py_ssize_t x;
2910-
if (_PyIndex_Check(v)) {
2926+
if (PyLong_CheckExact(v)) {
2927+
if (_PyLong_IsCompact((PyLongObject *)v)) {
2928+
x = _PyLong_CompactValue((PyLongObject *)v);
2929+
}
2930+
else {
2931+
x = PyLong_AsSsize_t(v);
2932+
if (x == -1 && _PyErr_Occurred(tstate)) {
2933+
assert(_PyErr_ExceptionMatches(tstate, PyExc_OverflowError));
2934+
_PyErr_Clear(tstate);
2935+
x = _PyLong_IsNegative((PyLongObject *)v)
2936+
? PY_SSIZE_T_MIN : PY_SSIZE_T_MAX;
2937+
}
2938+
}
2939+
}
2940+
else if (_PyIndex_Check(v)) {
29112941
x = PyNumber_AsSsize_t(v, NULL);
29122942
if (x == -1 && _PyErr_Occurred(tstate))
29132943
return 0;

Python/executor_cases.c.h

Lines changed: 22 additions & 29 deletions
Some generated files are not rendered by default. Learn more about customizing how changed files appear on GitHub.

0 commit comments

Comments
 (0)