Skip to content

Commit 7e116bd

Browse files
committed
bpo-36926: implement methoddescr_call without _PyMethodDef_RawFastCallDict
1 parent aacc77f commit 7e116bd

File tree

2 files changed

+53
-10
lines changed

2 files changed

+53
-10
lines changed

Objects/call.c

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -753,6 +753,7 @@ cfunction_call_varargs(PyObject *func, PyObject *args, PyObject *kwargs)
753753
{
754754
assert(!PyErr_Occurred());
755755
assert(kwargs == NULL || PyDict_Check(kwargs));
756+
assert(PyCFunction_GET_FLAGS(func) & METH_VARARGS);
756757

757758
PyCFunction meth = PyCFunction_GET_FUNCTION(func);
758759
PyObject *self = PyCFunction_GET_SELF(func);

Objects/descrobject.c

Lines changed: 52 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -227,14 +227,15 @@ getset_set(PyGetSetDescrObject *descr, PyObject *obj, PyObject *value)
227227
}
228228

229229
static PyObject *
230-
methoddescr_call(PyMethodDescrObject *descr, PyObject *args, PyObject *kwargs)
230+
methoddescr_call_varargs_keywords(PyMethodDescrObject *descr, PyObject *args, PyObject *kwargs)
231231
{
232-
Py_ssize_t nargs;
233-
PyObject *self, *result;
232+
assert(!PyErr_Occurred());
233+
assert(kwargs == NULL || PyDict_Check(kwargs));
234+
assert(descr->d_method->ml_flags & METH_VARARGS);
235+
assert(descr->d_method->ml_flags & METH_KEYWORDS);
234236

235237
/* Make sure that the first argument is acceptable as 'self' */
236-
assert(PyTuple_Check(args));
237-
nargs = PyTuple_GET_SIZE(args);
238+
Py_ssize_t nargs = PyTuple_GET_SIZE(args);
238239
if (nargs < 1) {
239240
PyErr_Format(PyExc_TypeError,
240241
"descriptor '%V' of '%.100s' "
@@ -243,7 +244,7 @@ methoddescr_call(PyMethodDescrObject *descr, PyObject *args, PyObject *kwargs)
243244
PyDescr_TYPE(descr)->tp_name);
244245
return NULL;
245246
}
246-
self = PyTuple_GET_ITEM(args, 0);
247+
PyObject *self = PyTuple_GET_ITEM(args, 0);
247248
if (!_PyObject_RealIsSubclass((PyObject *)Py_TYPE(self),
248249
(PyObject *)PyDescr_TYPE(descr))) {
249250
PyErr_Format(PyExc_TypeError,
@@ -255,10 +256,51 @@ methoddescr_call(PyMethodDescrObject *descr, PyObject *args, PyObject *kwargs)
255256
return NULL;
256257
}
257258

258-
result = _PyMethodDef_RawFastCallDict(descr->d_method, self,
259-
&_PyTuple_ITEMS(args)[1], nargs - 1,
260-
kwargs);
261-
result = _Py_CheckFunctionResult((PyObject *)descr, result, NULL);
259+
/* Remove self from args */
260+
PyObject *slicedargs = _PyTuple_FromArray(_PyTuple_ITEMS(args) + 1, nargs - 1);
261+
if (slicedargs == NULL) {
262+
return NULL;
263+
}
264+
265+
if (Py_EnterRecursiveCall(" while calling a Python object")) {
266+
Py_DECREF(slicedargs);
267+
return NULL;
268+
}
269+
270+
PyCFunctionWithKeywords meth = (PyCFunctionWithKeywords)(void(*)(void))descr->d_method->ml_meth;
271+
PyObject *result = meth(self, slicedargs, kwargs);
272+
273+
Py_LeaveRecursiveCall();
274+
Py_DECREF(slicedargs);
275+
276+
return _Py_CheckFunctionResult((PyObject *)descr, result, NULL);
277+
}
278+
279+
static PyObject *
280+
methoddescr_call(PyMethodDescrObject *descr, PyObject *args, PyObject *kwargs)
281+
{
282+
int flags = descr->d_method->ml_flags;
283+
if ((flags & (METH_VARARGS|METH_KEYWORDS)) == (METH_VARARGS|METH_KEYWORDS)) {
284+
/* For METH_VARARGS|METH_KEYWORDS, using FastCallKeywords would
285+
* be less optimal because the kwargs dict would be converted
286+
* to a tuple and then back to a dict. */
287+
return methoddescr_call_varargs_keywords(descr, args, kwargs);
288+
}
289+
290+
/* Use FastCallKeywords instead */
291+
Py_ssize_t nargs = PyTuple_GET_SIZE(args);
292+
PyObject *const *stack;
293+
PyObject *kwnames;
294+
if (_PyStack_UnpackDict(_PyTuple_ITEMS(args), nargs, kwargs, &stack, &kwnames) < 0) {
295+
return NULL;
296+
}
297+
298+
PyObject *result = _PyMethodDescr_FastCallKeywords((PyObject *)descr,
299+
stack, nargs, kwnames);
300+
if (stack != _PyTuple_ITEMS(args)) {
301+
PyMem_Free((PyObject **)stack);
302+
}
303+
Py_XDECREF(kwnames);
262304
return result;
263305
}
264306

0 commit comments

Comments
 (0)