bpo-38644: Add _PyObject_VectorcallTstate() (GH-17052) · python/cpython@7e43373 · GitHub
Skip to content

Commit 7e43373

Browse files
authored
bpo-38644: Add _PyObject_VectorcallTstate() (GH-17052)
* Add _PyObject_VectorcallTstate() function: similar to _PyObject_Vectorcall(), but with tstate parameter * Add tstate parameter to _PyObject_MakeTpCall()
1 parent befa032 commit 7e43373

6 files changed

Lines changed: 94 additions & 50 deletions

File tree

Include/cpython/abstract.h

Lines changed: 14 additions & 4 deletions

Modules/_functoolsmodule.c

Lines changed: 14 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -132,21 +132,25 @@ partial_dealloc(partialobject *pto)
132132
* if we would need to do that, we stop using vectorcall and fall back
133133
* to using partial_call() instead. */
134134
_Py_NO_INLINE static PyObject *
135-
partial_vectorcall_fallback(partialobject *pto, PyObject *const *args,
136-
size_t nargsf, PyObject *kwnames)
135+
partial_vectorcall_fallback(PyThreadState *tstate, partialobject *pto,
136+
PyObject *const *args, size_t nargsf,
137+
PyObject *kwnames)
137138
{
138139
pto->vectorcall = NULL;
139140
Py_ssize_t nargs = PyVectorcall_NARGS(nargsf);
140-
return _PyObject_MakeTpCall((PyObject *)pto, args, nargs, kwnames);
141+
return _PyObject_MakeTpCall(tstate, (PyObject *)pto,
142+
args, nargs, kwnames);
141143
}
142144

143145
static PyObject *
144146
partial_vectorcall(partialobject *pto, PyObject *const *args,
145147
size_t nargsf, PyObject *kwnames)
146148
{
149+
PyThreadState *tstate = _PyThreadState_GET();
150+
147151
/* pto->kw is mutable, so need to check every time */
148152
if (PyDict_GET_SIZE(pto->kw)) {
149-
return partial_vectorcall_fallback(pto, args, nargsf, kwnames);
153+
return partial_vectorcall_fallback(tstate, pto, args, nargsf, kwnames);
150154
}
151155

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

161165
/* Fast path if we're called without arguments */
162166
if (nargs_total == 0) {
163-
return _PyObject_Vectorcall(pto->fn, pto_args, pto_nargs, NULL);
167+
return _PyObject_VectorcallTstate(tstate, pto->fn,
168+
pto_args, pto_nargs, NULL);
164169
}
165170

166171
/* Fast path using PY_VECTORCALL_ARGUMENTS_OFFSET to prepend a single
@@ -169,7 +174,8 @@ partial_vectorcall(partialobject *pto, PyObject *const *args,
169174
PyObject **newargs = (PyObject **)args - 1;
170175
PyObject *tmp = newargs[0];
171176
newargs[0] = pto_args[0];
172-
PyObject *ret = _PyObject_Vectorcall(pto->fn, newargs, nargs + 1, kwnames);
177+
PyObject *ret = _PyObject_VectorcallTstate(tstate, pto->fn,
178+
newargs, nargs + 1, kwnames);
173179
newargs[0] = tmp;
174180
return ret;
175181
}
@@ -195,7 +201,8 @@ partial_vectorcall(partialobject *pto, PyObject *const *args,
195201
memcpy(stack, pto_args, pto_nargs * sizeof(PyObject*));
196202
memcpy(stack + pto_nargs, args, nargs_total * sizeof(PyObject*));
197203

198-
ret = _PyObject_Vectorcall(pto->fn, stack, pto_nargs + nargs, kwnames);
204+
ret = _PyObject_VectorcallTstate(tstate, pto->fn,
205+
stack, pto_nargs + nargs, kwnames);
199206
if (stack != small_stack) {
200207
PyMem_Free(stack);
201208
}

Objects/call.c

Lines changed: 7 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -104,7 +104,7 @@ _PyObject_FastCallDict(PyObject *callable, PyObject *const *args,
104104
vectorcallfunc func = _PyVectorcall_Function(callable);
105105
if (func == NULL) {
106106
/* Use tp_call instead */
107-
return _PyObject_MakeTpCall(callable, args, nargs, kwargs);
107+
return _PyObject_MakeTpCall(tstate, callable, args, nargs, kwargs);
108108
}
109109

110110
PyObject *res;
@@ -129,10 +129,10 @@ _PyObject_FastCallDict(PyObject *callable, PyObject *const *args,
129129

130130

131131
PyObject *
132-
_PyObject_MakeTpCall(PyObject *callable, PyObject *const *args, Py_ssize_t nargs, PyObject *keywords)
132+
_PyObject_MakeTpCall(PyThreadState *tstate, PyObject *callable,
133+
PyObject *const *args, Py_ssize_t nargs,
134+
PyObject *keywords)
133135
{
134-
PyThreadState *tstate = _PyThreadState_GET();
135-
136136
/* Slow path: build a temporary tuple for positional arguments and a
137137
* temporary dictionary for keyword arguments (if any) */
138138
ternaryfunc call = Py_TYPE(callable)->tp_call;
@@ -774,6 +774,7 @@ _PyObject_VectorcallMethod(PyObject *name, PyObject *const *args,
774774
assert(args != NULL);
775775
assert(PyVectorcall_NARGS(nargsf) >= 1);
776776

777+
PyThreadState *tstate = _PyThreadState_GET();
777778
PyObject *callable = NULL;
778779
/* Use args[0] as "self" argument */
779780
int unbound = _PyObject_GetMethod(args[0], name, &callable);
@@ -792,7 +793,8 @@ _PyObject_VectorcallMethod(PyObject *name, PyObject *const *args,
792793
args++;
793794
nargsf--;
794795
}
795-
PyObject *result = _PyObject_Vectorcall(callable, args, nargsf, kwnames);
796+
PyObject *result = _PyObject_VectorcallTstate(tstate, callable,
797+
args, nargsf, kwnames);
796798
Py_DECREF(callable);
797799
return result;
798800
}

Objects/classobject.c

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

33
#include "Python.h"
44
#include "pycore_object.h"
5+
#include "pycore_pyerrors.h"
56
#include "pycore_pymem.h"
67
#include "pycore_pystate.h"
78
#include "structmember.h"
@@ -37,25 +38,28 @@ method_vectorcall(PyObject *method, PyObject *const *args,
3738
size_t nargsf, PyObject *kwnames)
3839
{
3940
assert(Py_TYPE(method) == &PyMethod_Type);
40-
PyObject *self, *func, *result;
41-
self = PyMethod_GET_SELF(method);
42-
func = PyMethod_GET_FUNCTION(method);
41+
42+
PyThreadState *tstate = _PyThreadState_GET();
43+
PyObject *self = PyMethod_GET_SELF(method);
44+
PyObject *func = PyMethod_GET_FUNCTION(method);
4345
Py_ssize_t nargs = PyVectorcall_NARGS(nargsf);
4446

47+
PyObject *result;
4548
if (nargsf & PY_VECTORCALL_ARGUMENTS_OFFSET) {
4649
/* PY_VECTORCALL_ARGUMENTS_OFFSET is set, so we are allowed to mutate the vector */
4750
PyObject **newargs = (PyObject**)args - 1;
4851
nargs += 1;
4952
PyObject *tmp = newargs[0];
5053
newargs[0] = self;
51-
result = _PyObject_Vectorcall(func, newargs, nargs, kwnames);
54+
result = _PyObject_VectorcallTstate(tstate, func, newargs,
55+
nargs, kwnames);
5256
newargs[0] = tmp;
5357
}
5458
else {
5559
Py_ssize_t nkwargs = (kwnames == NULL) ? 0 : PyTuple_GET_SIZE(kwnames);
5660
Py_ssize_t totalargs = nargs + nkwargs;
5761
if (totalargs == 0) {
58-
return _PyObject_Vectorcall(func, &self, 1, NULL);
62+
return _PyObject_VectorcallTstate(tstate, func, &self, 1, NULL);
5963
}
6064

6165
PyObject *newargs_stack[_PY_FASTCALL_SMALL_STACK];
@@ -66,7 +70,7 @@ method_vectorcall(PyObject *method, PyObject *const *args,
6670
else {
6771
newargs = PyMem_Malloc((totalargs+1) * sizeof(PyObject *));
6872
if (newargs == NULL) {
69-
PyErr_NoMemory();
73+
_PyErr_NoMemory(tstate);
7074
return NULL;
7175
}
7276
}
@@ -77,7 +81,8 @@ method_vectorcall(PyObject *method, PyObject *const *args,
7781
* undefined behaviour. */
7882
assert(args != NULL);
7983
memcpy(newargs + 1, args, totalargs * sizeof(PyObject *));
80-
result = _PyObject_Vectorcall(func, newargs, nargs+1, kwnames);
84+
result = _PyObject_VectorcallTstate(tstate, func,
85+
newargs, nargs+1, kwnames);
8186
if (newargs != newargs_stack) {
8287
PyMem_Free(newargs);
8388
}

Objects/typeobject.c

Lines changed: 16 additions & 10 deletions

0 commit comments

Comments
 (0)