@@ -226,80 +226,199 @@ getset_set(PyGetSetDescrObject *descr, PyObject *obj, PyObject *value)
226226 return -1 ;
227227}
228228
229- static PyObject *
230- methoddescr_call (PyMethodDescrObject * descr , PyObject * args , PyObject * kwargs )
231- {
232- Py_ssize_t nargs ;
233- PyObject * self , * result ;
234229
235- /* Make sure that the first argument is acceptable as 'self' */
236- assert (PyTuple_Check (args ));
237- nargs = PyTuple_GET_SIZE (args );
230+ /* Vectorcall functions for each of the PyMethodDescr calling conventions.
231+ *
232+ * First, common helpers
233+ */
234+ static const char *
235+ get_name (PyObject * func ) {
236+ assert (PyObject_TypeCheck (func , & PyMethodDescr_Type ));
237+ return ((PyMethodDescrObject * )func )-> d_method -> ml_name ;
238+ }
239+
240+ typedef void (* funcptr )(void );
241+
242+ static inline int
243+ method_check_args (PyObject * func , PyObject * const * args , Py_ssize_t nargs , PyObject * kwnames )
244+ {
245+ assert (!PyErr_Occurred ());
246+ assert (PyObject_TypeCheck (func , & PyMethodDescr_Type ));
238247 if (nargs < 1 ) {
239248 PyErr_Format (PyExc_TypeError ,
240- "descriptor '%V ' of '%.100s' "
249+ "descriptor '%.200s ' of '%.100s' "
241250 "object needs an argument" ,
242- descr_name ((PyDescrObject * )descr ), "?" ,
243- PyDescr_TYPE (descr )-> tp_name );
244- return NULL ;
251+ get_name (func ), PyDescr_TYPE (func )-> tp_name );
252+ return -1 ;
245253 }
246- self = PyTuple_GET_ITEM ( args , 0 ) ;
254+ PyObject * self = args [ 0 ] ;
247255 if (!_PyObject_RealIsSubclass ((PyObject * )Py_TYPE (self ),
248- (PyObject * )PyDescr_TYPE (descr ))) {
256+ (PyObject * )PyDescr_TYPE (func )))
257+ {
249258 PyErr_Format (PyExc_TypeError ,
250- "descriptor '%V ' for '%.100s' objects "
259+ "descriptor '%.200s ' for '%.100s' objects "
251260 "doesn't apply to a '%.100s' object" ,
252- descr_name ((PyDescrObject * )descr ), "?" ,
253- PyDescr_TYPE (descr )-> tp_name ,
254- self -> ob_type -> tp_name );
261+ get_name (func ), PyDescr_TYPE (func )-> tp_name ,
262+ Py_TYPE (self )-> tp_name );
263+ return -1 ;
264+ }
265+ if (kwnames && PyTuple_GET_SIZE (kwnames )) {
266+ PyErr_Format (PyExc_TypeError ,
267+ "%.200s() takes no keyword arguments" , get_name (func ));
268+ return -1 ;
269+ }
270+ return 0 ;
271+ }
272+
273+ static inline funcptr
274+ method_enter_call (PyObject * func )
275+ {
276+ if (Py_EnterRecursiveCall (" while calling a Python object" )) {
255277 return NULL ;
256278 }
279+ return (funcptr )((PyMethodDescrObject * )func )-> d_method -> ml_meth ;
280+ }
257281
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 );
282+ /* Now the actual vectorcall functions */
283+ static PyObject *
284+ method_vectorcall_VARARGS (
285+ PyObject * func , PyObject * const * args , size_t nargsf , PyObject * kwnames )
286+ {
287+ Py_ssize_t nargs = PyVectorcall_NARGS (nargsf );
288+ if (method_check_args (func , args , nargs , kwnames )) {
289+ return NULL ;
290+ }
291+ PyObject * argstuple = _PyTuple_FromArray (args + 1 , nargs - 1 );
292+ if (argstuple == NULL ) {
293+ return NULL ;
294+ }
295+ PyCFunction meth = (PyCFunction )method_enter_call (func );
296+ if (meth == NULL ) {
297+ Py_DECREF (argstuple );
298+ return NULL ;
299+ }
300+ PyObject * result = meth (args [0 ], argstuple );
301+ Py_DECREF (argstuple );
302+ Py_LeaveRecursiveCall ();
262303 return result ;
263304}
264305
265- // same to methoddescr_call(), but use FASTCALL convention.
266- PyObject *
267- _PyMethodDescr_Vectorcall (PyObject * descrobj ,
268- PyObject * const * args , size_t nargsf ,
269- PyObject * kwnames )
306+ static PyObject *
307+ method_vectorcall_VARARGS_KEYWORDS (
308+ PyObject * func , PyObject * const * args , size_t nargsf , PyObject * kwnames )
270309{
271- assert (Py_TYPE (descrobj ) == & PyMethodDescr_Type );
272- PyMethodDescrObject * descr = (PyMethodDescrObject * )descrobj ;
273- PyObject * self , * result ;
310+ Py_ssize_t nargs = PyVectorcall_NARGS (nargsf );
311+ if (method_check_args (func , args , nargs , NULL )) {
312+ return NULL ;
313+ }
314+ PyObject * argstuple = _PyTuple_FromArray (args + 1 , nargs - 1 );
315+ if (argstuple == NULL ) {
316+ return NULL ;
317+ }
318+ PyObject * result = NULL ;
319+ /* Create a temporary dict for keyword arguments */
320+ PyObject * kwdict = NULL ;
321+ if (kwnames != NULL && PyTuple_GET_SIZE (kwnames ) > 0 ) {
322+ kwdict = _PyStack_AsDict (args + nargs , kwnames );
323+ if (kwdict == NULL ) {
324+ goto exit ;
325+ }
326+ }
327+ PyCFunctionWithKeywords meth = (PyCFunctionWithKeywords )
328+ method_enter_call (func );
329+ if (meth == NULL ) {
330+ goto exit ;
331+ }
332+ result = meth (args [0 ], argstuple , kwdict );
333+ Py_LeaveRecursiveCall ();
334+ exit :
335+ Py_DECREF (argstuple );
336+ Py_XDECREF (kwdict );
337+ return result ;
338+ }
339+
340+ static PyObject *
341+ method_vectorcall_FASTCALL (
342+ PyObject * func , PyObject * const * args , size_t nargsf , PyObject * kwnames )
343+ {
344+ Py_ssize_t nargs = PyVectorcall_NARGS (nargsf );
345+ if (method_check_args (func , args , nargs , kwnames )) {
346+ return NULL ;
347+ }
348+ _PyCFunctionFast meth = (_PyCFunctionFast )
349+ method_enter_call (func );
350+ if (meth == NULL ) {
351+ return NULL ;
352+ }
353+ PyObject * result = meth (args [0 ], args + 1 , nargs - 1 );
354+ Py_LeaveRecursiveCall ();
355+ return result ;
356+ }
274357
358+ static PyObject *
359+ method_vectorcall_FASTCALL_KEYWORDS (
360+ PyObject * func , PyObject * const * args , size_t nargsf , PyObject * kwnames )
361+ {
275362 Py_ssize_t nargs = PyVectorcall_NARGS (nargsf );
276- /* Make sure that the first argument is acceptable as 'self' */
277- if (nargs < 1 ) {
278- PyErr_Format (PyExc_TypeError ,
279- "descriptor '%V' of '%.100s' "
280- "object needs an argument" ,
281- descr_name ((PyDescrObject * )descr ), "?" ,
282- PyDescr_TYPE (descr )-> tp_name );
363+ if (method_check_args (func , args , nargs , NULL )) {
283364 return NULL ;
284365 }
285- self = args [0 ];
286- if (!_PyObject_RealIsSubclass ((PyObject * )Py_TYPE (self ),
287- (PyObject * )PyDescr_TYPE (descr ))) {
366+ _PyCFunctionFastWithKeywords meth = (_PyCFunctionFastWithKeywords )
367+ method_enter_call (func );
368+ if (meth == NULL ) {
369+ return NULL ;
370+ }
371+ PyObject * result = meth (args [0 ], args + 1 , nargs - 1 , kwnames );
372+ Py_LeaveRecursiveCall ();
373+ return result ;
374+ }
375+
376+ static PyObject *
377+ method_vectorcall_NOARGS (
378+ PyObject * func , PyObject * const * args , size_t nargsf , PyObject * kwnames )
379+ {
380+ Py_ssize_t nargs = PyVectorcall_NARGS (nargsf );
381+ if (method_check_args (func , args , nargs , kwnames )) {
382+ return NULL ;
383+ }
384+ if (nargs != 1 ) {
288385 PyErr_Format (PyExc_TypeError ,
289- "descriptor '%V' for '%.100s' objects "
290- "doesn't apply to a '%.100s' object" ,
291- descr_name (( PyDescrObject * ) descr ), "?" ,
292- PyDescr_TYPE ( descr ) -> tp_name ,
293- self -> ob_type -> tp_name );
386+ "%.200s() takes no arguments (%zd given)" , get_name ( func ), nargs - 1 );
387+ return NULL ;
388+ }
389+ PyCFunction meth = ( PyCFunction ) method_enter_call ( func );
390+ if ( meth == NULL ) {
294391 return NULL ;
295392 }
393+ PyObject * result = meth (args [0 ], NULL );
394+ Py_LeaveRecursiveCall ();
395+ return result ;
396+ }
296397
297- result = _PyMethodDef_RawFastCallKeywords (descr -> d_method , self ,
298- args + 1 , nargs - 1 , kwnames );
299- result = _Py_CheckFunctionResult ((PyObject * )descr , result , NULL );
398+ static PyObject *
399+ method_vectorcall_O (
400+ PyObject * func , PyObject * const * args , size_t nargsf , PyObject * kwnames )
401+ {
402+ Py_ssize_t nargs = PyVectorcall_NARGS (nargsf );
403+ if (method_check_args (func , args , nargs , kwnames )) {
404+ return NULL ;
405+ }
406+ if (nargs != 2 ) {
407+ PyErr_Format (PyExc_TypeError ,
408+ "%.200s() takes exactly one argument (%zd given)" ,
409+ get_name (func ), nargs - 1 );
410+ return NULL ;
411+ }
412+ PyCFunction meth = (PyCFunction )method_enter_call (func );
413+ if (meth == NULL ) {
414+ return NULL ;
415+ }
416+ PyObject * result = meth (args [0 ], args [1 ]);
417+ Py_LeaveRecursiveCall ();
300418 return result ;
301419}
302420
421+
303422/* Instances of classmethod_descriptor are unlikely to be called directly.
304423 For one, the analogous class "classmethod" (for Python classes) is not
305424 callable. Second, users are not likely to access a classmethod_descriptor
@@ -540,7 +659,7 @@ PyTypeObject PyMethodDescr_Type = {
540659 0 , /* tp_as_sequence */
541660 0 , /* tp_as_mapping */
542661 0 , /* tp_hash */
543- ( ternaryfunc ) methoddescr_call , /* tp_call */
662+ PyVectorcall_Call , /* tp_call */
544663 0 , /* tp_str */
545664 PyObject_GenericGetAttr , /* tp_getattro */
546665 0 , /* tp_setattro */
@@ -738,13 +857,40 @@ descr_new(PyTypeObject *descrtype, PyTypeObject *type, const char *name)
738857PyObject *
739858PyDescr_NewMethod (PyTypeObject * type , PyMethodDef * method )
740859{
860+ /* Figure out correct vectorcall function to use */
861+ vectorcallfunc vectorcall ;
862+ switch (method -> ml_flags & (METH_VARARGS | METH_FASTCALL | METH_NOARGS | METH_O | METH_KEYWORDS ))
863+ {
864+ case METH_VARARGS :
865+ vectorcall = method_vectorcall_VARARGS ;
866+ break ;
867+ case METH_VARARGS | METH_KEYWORDS :
868+ vectorcall = method_vectorcall_VARARGS_KEYWORDS ;
869+ break ;
870+ case METH_FASTCALL :
871+ vectorcall = method_vectorcall_FASTCALL ;
872+ break ;
873+ case METH_FASTCALL | METH_KEYWORDS :
874+ vectorcall = method_vectorcall_FASTCALL_KEYWORDS ;
875+ break ;
876+ case METH_NOARGS :
877+ vectorcall = method_vectorcall_NOARGS ;
878+ break ;
879+ case METH_O :
880+ vectorcall = method_vectorcall_O ;
881+ break ;
882+ default :
883+ PyErr_SetString (PyExc_SystemError , "bad call flags" );
884+ return NULL ;
885+ }
886+
741887 PyMethodDescrObject * descr ;
742888
743889 descr = (PyMethodDescrObject * )descr_new (& PyMethodDescr_Type ,
744890 type , method -> ml_name );
745891 if (descr != NULL ) {
746892 descr -> d_method = method ;
747- descr -> vectorcall = _PyMethodDescr_Vectorcall ;
893+ descr -> vectorcall = vectorcall ;
748894 }
749895 return (PyObject * )descr ;
750896}
0 commit comments