8000 bpo-37207: Use vectorcall for range() (GH-18464) · python/cpython@6e35da9 · GitHub
[go: up one dir, main page]

Skip to content

Commit 6e35da9

Browse files
authored
bpo-37207: Use vectorcall for range() (GH-18464)
This continues the `range()` part of #13930. The complete pull request is stalled on discussions around dicts, but `range()` should not be controversial. (And I plan to open PRs for other parts if this is merged.) On top of Mark's change, I unified `range_new` and `range_vectorcall`, which had a lot of duplicate code. https://bugs.python.org/issue37207
1 parent 24bba8c commit 6e35da9

File tree

2 files changed

+35
-17
lines changed

2 files changed

+35
-17
lines changed
Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,2 @@
1+
Speed up calls to ``range()`` by about 30%, by using the
2+
PEP 590 ``vectorcall`` calling convention. Patch by Mark Shannon.

Objects/rangeobject.c

Lines changed: 33 additions & 17 deletions
Original file line numberDiff line numberDiff line change
@@ -2,6 +2,7 @@
22

33
#include "Python.h"
44
#include "structmember.h"
5+
#include "pycore_tupleobject.h"
56

67
/* Support objects whose length is > PY_SSIZE_T_MAX.
78
@@ -71,43 +72,35 @@ make_range_object(PyTypeObject *type, PyObject *start,
7172
range(0, 5, -1)
7273
*/
7374
static PyObject *
74-
range_new(PyTypeObject *type, PyObject *args, PyObject *kw)
75+
range_from_array(PyTypeObject *type, PyObject *const *args, Py_ssize_t num_args)
7576
{
7677
rangeobject *obj;
7778
PyObject *start = NULL, *stop = NULL, *step = NULL;
7879

79-
if (!_PyArg_NoKeywords("range", kw))
80-
return NULL;
81-
82-
Py_ssize_t num_args = PyTuple_GET_SIZE(args);
8380
switch (num_args) {
8481
case 3:
85-
step = PyTuple_GET_ITEM(args, 2);
82+
step = args[2];
8683
/* fallthrough */
8784
case 2:
88-
start = PyTuple_GET_ITEM(args, 0);
89-
start = PyNumber_Index(start);
85+
/* Convert borrowed refs to owned refs */
86+
start = PyNumber_Index(args[0]);
9087
if (!start) {
9188
return NULL;
9289
}
93-
94-
stop = PyTuple_GET_ITEM(args, 1);
95-
stop = PyNumber_Index(stop);
90+
stop = PyNumber_Index(args[1]);
9691
if (!stop) {
9792
Py_DECREF(start);
9893
return NULL;
9994
}
100-
101-
step = validate_step(step);
95+
step = validate_step(step); /* Caution, this can clear exceptions */
10296
if (!step) {
10397
Py_DECREF(start);
10498
Py_DECREF(stop);
10599
return NULL;
106100
}
107101
break;
108102
case 1:
109-
stop = PyTuple_GET_ITEM(args, 0);
110-
stop = PyNumber_Index(stop);
103+
stop = PyNumber_Index(args[0]);
111104
if (!stop) {
112105
return NULL;
113106
}
@@ -126,10 +119,10 @@ range_new(PyTypeObject *type, PyObject *args, PyObject *kw)
126119
num_args);
127120
return NULL;
128121
}
129-
130122
obj = make_range_object(type, start, stop, step);
131-
if (obj != NULL)
123+
if (obj != NULL) {
132124
return (PyObject *) obj;
125+
}
133126

134127
/* Failed to create object, release attributes */
135128
Py_DECREF(start);
@@ -138,6 +131,28 @@ range_new(PyTypeObject *type, PyObject *args, PyObject *kw)
138131
return NULL;
139132
}
140133

134+
static PyObject *
135+
range_new(PyTypeObject *type, PyObject *args, PyObject *kw)
136+
{
137+
if (!_PyArg_NoKeywords("range", kw))
138+
return NULL;
139+
140+
return range_from_array(type, _PyTuple_ITEMS(args), PyTuple_GET_SIZE(args));
141+
}
142+
143+
144+
static PyObject *
145+
range_vectorcall(PyTypeObject *type, PyObject *const *args,
146+
size_t nargsf, PyObject *kwnames)
147+
{
148+
Py_ssize_t nargs = PyVectorcall_NARGS(nargsf);
149+
if (kwnames && PyTuple_GET_SIZE(kwnames) != 0) {
150+
PyErr_Format(PyExc_TypeError, "range() takes no keyword arguments");
151+
return NULL;
152+
}
153+
return range_from_array(type, args, nargs);
154+
}
155+
141156
PyDoc_STRVAR(range_doc,
142157
"range(stop) -> range object\n\
143158
range(start, stop[, step]) -> range object\n\
@@ -719,6 +734,7 @@ PyTypeObject PyRange_Type = {
719734
0, /* tp_init */
720735
0, /* tp_alloc */
721736
range_new, /* tp_new */
737+
.tp_vectorcall = (vectorcallfunc)range_vectorcall
722738
};
723739

724740
/*********************** range Iterator **************************/

0 commit comments

Comments
 (0)
0