bpo-38644: Add _PyObject_VectorcallTstate() by vstinner · Pull Request #17052 · python/cpython · GitHub
Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
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
18 changes: 14 additions & 4 deletions Include/cpython/abstract.h
21 changes: 14 additions & 7 deletions Modules/_functoolsmodule.c
Original file line number Diff line number Diff line change
Expand Up @@ -132,21 +132,25 @@ partial_dealloc(partialobject *pto)
* if we would need to do that, we stop using vectorcall and fall back
* to using partial_call() instead. */
_Py_NO_INLINE static PyObject *
partial_vectorcall_fallback(partialobject *pto, PyObject *const *args,
size_t nargsf, PyObject *kwnames)
partial_vectorcall_fallback(PyThreadState *tstate, partialobject *pto,
PyObject *const *args, size_t nargsf,
PyObject *kwnames)
{
pto->vectorcall = NULL;
Py_ssize_t nargs = PyVectorcall_NARGS(nargsf);
return _PyObject_MakeTpCall((PyObject *)pto, args, nargs, kwnames);
return _PyObject_MakeTpCall(tstate, (PyObject *)pto,
args, nargs, kwnames);
}

static PyObject *
partial_vectorcall(partialobject *pto, PyObject *const *args,
size_t nargsf, PyObject *kwnames)
{
PyThreadState *tstate = _PyThreadState_GET();

/* pto->kw is mutable, so need to check every time */
if (PyDict_GET_SIZE(pto->kw)) {
return partial_vectorcall_fallback(pto, args, nargsf, kwnames);
return partial_vectorcall_fallback(tstate, pto, args, nargsf, kwnames);
}

Py_ssize_t nargs = PyVectorcall_NARGS(nargsf);
Expand All @@ -160,7 +164,8 @@ partial_vectorcall(partialobject *pto, PyObject *const *args,

/* Fast path if we're called without arguments */
if (nargs_total == 0) {
return _PyObject_Vectorcall(pto->fn, pto_args, pto_nargs, NULL);
return _PyObject_VectorcallTstate(tstate, pto->fn,
pto_args, pto_nargs, NULL);
}

/* Fast path using PY_VECTORCALL_ARGUMENTS_OFFSET to prepend a single
Expand All @@ -169,7 +174,8 @@ partial_vectorcall(partialobject *pto, PyObject *const *args,
PyObject **newargs = (PyObject **)args - 1;
PyObject *tmp = newargs[0];
newargs[0] = pto_args[0];
PyObject *ret = _PyObject_Vectorcall(pto->fn, newargs, nargs + 1, kwnames);
PyObject *ret = _PyObject_VectorcallTstate(tstate, pto->fn,
newargs, nargs + 1, kwnames);
newargs[0] = tmp;
return ret;
}
Expand All @@ -195,7 +201,8 @@ partial_vectorcall(partialobject *pto, PyObject *const *args,
memcpy(stack, pto_args, pto_nargs * sizeof(PyObject*));
memcpy(stack + pto_nargs, args, nargs_total * sizeof(PyObject*));

ret = _PyObject_Vectorcall(pto->fn, stack, pto_nargs + nargs, kwnames);
ret = _PyObject_VectorcallTstate(tstate, pto->fn,
stack, pto_nargs + nargs, kwnames);
if (stack != small_stack) {
PyMem_Free(stack);
}
Expand Down
12 changes: 7 additions & 5 deletions Objects/call.c
Original file line number Diff line number Diff line change
Expand Up @@ -104,7 +104,7 @@ _PyObject_FastCallDict(PyObject *callable, PyObject *const *args,
vectorcallfunc func = _PyVectorcall_Function(callable);
if (func == NULL) {
/* Use tp_call instead */
return _PyObject_MakeTpCall(callable, args, nargs, kwargs);
return _PyObject_MakeTpCall(tstate, callable, args, nargs, kwargs);
}

PyObject *res;
Expand All @@ -129,10 +129,10 @@ _PyObject_FastCallDict(PyObject *callable, PyObject *const *args,


PyObject *
_PyObject_MakeTpCall(PyObject *callable, PyObject *const *args, Py_ssize_t nargs, PyObject *keywords)
_PyObject_MakeTpCall(PyThreadState *tstate, PyObject *callable,
PyObject *const *args, Py_ssize_t nargs,
PyObject *keywords)
{
PyThreadState *tstate = _PyThreadState_GET();

/* Slow path: build a temporary tuple for positional arguments and a
* temporary dictionary for keyword arguments (if any) */
ternaryfunc call = Py_TYPE(callable)->tp_call;
Expand Down Expand Up @@ -774,6 +774,7 @@ _PyObject_VectorcallMethod(PyObject *name, PyObject *const *args,
assert(args != NULL);
assert(PyVectorcall_NARGS(nargsf) >= 1);

PyThreadState *tstate = _PyThreadState_GET();
PyObject *callable = NULL;
/* Use args[0] as "self" argument */
int unbound = _PyObject_GetMethod(args[0], name, &callable);
Expand All @@ -792,7 +793,8 @@ _PyObject_VectorcallMethod(PyObject *name, PyObject *const *args,
args++;
nargsf--;
}
PyObject *result = _PyObject_Vectorcall(callable, args, nargsf, kwnames);
PyObject *result = _PyObject_VectorcallTstate(tstate, callable,
args, nargsf, kwnames);
Py_DECREF(callable);
return result;
}
Expand Down
19 changes: 12 additions & 7 deletions Objects/classobject.c
Original file line number Diff line number Diff line change
Expand Up @@ -2,6 +2,7 @@

#include "Python.h"
#include "pycore_object.h"
#include "pycore_pyerrors.h"
#include "pycore_pymem.h"
#include "pycore_pystate.h"
#include "structmember.h"
Expand Down Expand Up @@ -37,25 +38,28 @@ method_vectorcall(PyObject *method, PyObject *const *args,
size_t nargsf, PyObject *kwnames)
{
assert(Py_TYPE(method) == &PyMethod_Type);
PyObject *self, *func, *result;
self = PyMethod_GET_SELF(method);
func = PyMethod_GET_FUNCTION(method);

PyThreadState *tstate = _PyThreadState_GET();
PyObject *self = PyMethod_GET_SELF(method);
PyObject *func = PyMethod_GET_FUNCTION(method);
Py_ssize_t nargs = PyVectorcall_NARGS(nargsf);

PyObject *result;
if (nargsf & PY_VECTORCALL_ARGUMENTS_OFFSET) {
/* PY_VECTORCALL_ARGUMENTS_OFFSET is set, so we are allowed to mutate the vector */
PyObject **newargs = (PyObject**)args - 1;
nargs += 1;
PyObject *tmp = newargs[0];
newargs[0] = self;
result = _PyObject_Vectorcall(func, newargs, nargs, kwnames);
result = _PyObject_VectorcallTstate(tstate, func, newargs,
nargs, kwnames);
newargs[0] = tmp;
}
else {
Py_ssize_t nkwargs = (kwnames == NULL) ? 0 : PyTuple_GET_SIZE(kwnames);
Py_ssize_t totalargs = nargs + nkwargs;
if (totalargs == 0) {
return _PyObject_Vectorcall(func, &self, 1, NULL);
return _PyObject_VectorcallTstate(tstate, func, &self, 1, NULL);
}

PyObject *newargs_stack[_PY_FASTCALL_SMALL_STACK];
Expand All @@ -66,7 +70,7 @@ method_vectorcall(PyObject *method, PyObject *const *args,
else {
newargs = PyMem_Malloc((totalargs+1) * sizeof(PyObject *));
if (newargs == NULL) {
PyErr_NoMemory();
_PyErr_NoMemory(tstate);
return NULL;
}
}
Expand All @@ -77,7 +81,8 @@ method_vectorcall(PyObject *method, PyObject *const *args,
* undefined behaviour. */
assert(args != NULL);
memcpy(newargs + 1, args, totalargs * sizeof(PyObject *));
result = _PyObject_Vectorcall(func, newargs, nargs+1, kwnames);
result = _PyObject_VectorcallTstate(tstate, func,
newargs, nargs+1, kwnames);
if (newargs != newargs_stack) {
PyMem_Free(newargs);
}
Expand Down
26 changes: 16 additions & 10 deletions Objects/typeobject.c
Loading