8000 bpo-37207: Use vectorcall for range() by encukou · Pull Request #18464 · python/cpython · GitHub
[go: up one dir, main page]

Skip to content

bpo-37207: Use vectorcall for range() #18464

New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Merged
merged 5 commits into from
Feb 18, 2020
Merged
Changes from 1 commit
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
Prev Previous commit
Next Next commit
Unify implementations of range_new and range_vectorcall
  • Loading branch information
encukou committed Feb 11, 2020
commit 804e18c1bc5f525095f131d3cbc6a9873b7b692d
87 changes: 21 additions & 66 deletions Objects/rangeobject.c
Original file line number Diff line number Diff line change
Expand Up @@ -2,6 +2,7 @@

#include "Python.h"
#include "structmember.h"
#include "pycore_tupleobject.h"

/* Support objects whose length is > PY_SSIZE_T_MAX.

Expand Down Expand Up @@ -71,43 +72,35 @@ make_range_object(PyTypeObject *type, PyObject *start,
range(0, 5, -1)
*/
static PyObject *
range_new(PyTypeObject *type, PyObject *args, PyObject *kw)
range_from_array(PyTypeObject *type, PyObject *const *args, size_t num_args)
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I would prefer to use Py_ssize_t type for num_args. Usually, it's called "nargs", but I'm fine with "num_args" ;-)

Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Right, Py_ssize_t is more consistent.
But I find num_args more descriptive, so I'll keep that name.

{
rangeobject *obj;
PyObject *start = NULL, *stop = NULL, *step = NULL;

if (!_PyArg_NoKeywords("range", kw))
return NULL;

Py_ssize_t num_args = PyTuple_GET_SIZE(args);
switch (num_args) {
case 3:
step = PyTuple_GET_ITEM(args, 2);
step = args[2];
/* fallthrough */
case 2:
start = PyTuple_GET_ITEM(args, 0);
start = PyNumber_Index(start);
/* Convert borrowed refs to owned refs */
start = PyNumber_Index(args[0]);
if (!start) {
return NULL;
}

stop = PyTuple_GET_ITEM(args, 1);
stop = PyNumber_Index(stop);
stop = PyNumber_Index(args[1]);
if (!stop) {
Py_DECREF(start);
return NULL;
}

step = validate_step(step);
step = validate_step(step); /* Caution, this can clear exceptions */
if (!step) {
Py_DECREF(start);
Py_DECREF(stop);
return NULL;
}
break;
case 1:
stop = PyTuple_GET_ITEM(args, 0);
stop = PyNumber_Index(stop);
stop = PyNumber_Index(args[0]);
if (!stop) {
return NULL;
}
Expand All @@ -122,14 +115,14 @@ range_new(PyTypeObject *type, PyObject *args, PyObject *kw)
return NULL;
default:
PyErr_Format(PyExc_TypeError,
"range expected at most 3 arguments, got %zd",
"range expected at most 3 arguments, got %zu",
num_args);
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

It should be reset to %zd, since num_args is signed, no?

Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

You're right.

return NULL;
}

obj = make_range_object(type, start, stop, step);
if (obj != NULL)
if (obj != NULL) {
return (PyObject *) obj;
}

/* Failed to create object, release attributes */
Py_DECREF(start);
Expand All @@ -138,64 +131,26 @@ range_new(PyTypeObject *type, PyObject *args, PyObject *kw)
return NULL;
}

static PyObject *
range_new(PyTypeObject *type, PyObject *args, PyObject *kw)
{
if (!_PyArg_NoKeywords("range", kw))
return NULL;

return range_from_array(type, _PyTuple_ITEMS(args), PyTuple_GET_SIZE(args));
}


static PyObject *
range_vectorcall(PyTypeObject *type, PyObject *const *args,
size_t nargsf, PyObject *kwnames)
{
rangeobject *obj;
size_t nargs = PyVectorcall_NARGS(nargsf);
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Oh, I didn't expect a size_t here. I opened an issue to discuss PyVectorcall_NARGS() return type: https://bugs.python.org/issue39611

Copy link
Member Author
@encukou encukou Feb 18, 2020

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

The return type already is Py_ssize_t. The bug was only in this patch.
(When Mark was originally writing the patch, there was a discussion of Py_ssize_t vs. size_t. Mark is a big proponent of the unsigned type, which is more correct. But also much less compatible with the existing codebase.)

PyObject *start = NULL, *stop = NULL, *step = NULL;
if (kwnames && PyTuple_GET_SIZE(kwnames) != 0) {
PyErr_Format(PyExc_TypeError, "range() takes no keyword arguments");
return NULL;
}
switch(nargs) {
case 0:
PyErr_Format(PyExc_TypeError, "range() expected 1 arguments, got 0");
return NULL;
case 1:
stop = PyNumber_Index(args[0]);
if (!stop)
return NULL;
Py_INCREF(_PyLong_Zero);
start = _PyLong_Zero;
Py_INCREF(_PyLong_One);
step = _PyLong_One;
break;
case 3:
step = args[2];
//Intentional fall through
case 2:
/* Convert borrowed refs to owned refs */
start = PyNumber_Index(args[0]);
if (!start)
return NULL;
stop = PyNumber_Index(args[1]);
if (!stop) {
Py_DECREF(start);
return NULL;
}
step = validate_step(step); /* Caution, this can clear exceptions */
if (!step) {
Py_DECREF(start);
Py_DECREF(stop);
return NULL;
}
break;
default:
PyErr_Format(PyExc_TypeError, "range() expected at most 3 arguments, got %zu", nargs);
return NULL;
}
obj = make_range_object(type, start, stop, step);
if (obj != NULL)
return (PyObject *) obj;

/* Failed to create object, release attributes */
Py_DECREF(start);
Py_DECREF(stop);
Py_DECREF(step);
return NULL;
return range_from_array(type, args, nargs);
}

PyDoc_STRVAR(range_doc,
Expand Down
0