@@ -227,14 +227,15 @@ getset_set(PyGetSetDescrObject *descr, PyObject *obj, PyObject *value)
227
227
}
228
228
229
229
static PyObject *
230
- methoddescr_call (PyMethodDescrObject * descr , PyObject * args , PyObject * kwargs )
230
+ methoddescr_call_varargs_keywords (PyMethodDescrObject * descr , PyObject * args , PyObject * kwargs )
231
231
{
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 );
234
236
235
237
/* 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 );
238
239
if (nargs < 1 ) {
239
240
PyErr_Format (PyExc_TypeError ,
240
241
"descriptor '%V' of '%.100s' "
@@ -243,7 +244,7 @@ methoddescr_call(PyMethodDescrObject *descr, PyObject *args, PyObject *kwargs)
243
244
PyDescr_TYPE (descr )-> tp_name );
244
245
return NULL ;
245
246
}
246
- self = PyTuple_GET_ITEM (args , 0 );
247
+ PyObject * self = PyTuple_GET_ITEM (args , 0 );
247
248
if (!_PyObject_RealIsSubclass ((PyObject * )Py_TYPE (self ),
248
249
(PyObject * )PyDescr_TYPE (descr ))) {
249
250
PyErr_Format (PyExc_TypeError ,
@@ -255,10 +256,51 @@ methoddescr_call(PyMethodDescrObject *descr, PyObject *args, PyObject *kwargs)
255
256
return NULL ;
256
257
}
257
258
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 );
262
304
return result ;
263
305
}
264
306
0 commit comments