@@ -226,80 +226,199 @@ getset_set(PyGetSetDescrObject *descr, PyObject *obj, PyObject *value)
226
226
return -1 ;
227
227
}
228
228
229
- static PyObject *
230
- methoddescr_call (PyMethodDescrObject * descr , PyObject * args , PyObject * kwargs )
231
- {
232
- Py_ssize_t nargs ;
233
- PyObject * self , * result ;
234
229
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 ));
238
247
if (nargs < 1 ) {
239
248
PyErr_Format (PyExc_TypeError ,
240
- "descriptor '%V ' of '%.100s' "
249
+ "descriptor '%.200s ' of '%.100s' "
241
250
"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 ;
245
253
}
246
- self = PyTuple_GET_ITEM ( args , 0 ) ;
254
+ PyObject * self = args [ 0 ] ;
247
255
if (!_PyObject_RealIsSubclass ((PyObject * )Py_TYPE (self ),
248
- (PyObject * )PyDescr_TYPE (descr ))) {
256
+ (PyObject * )PyDescr_TYPE (func )))
257
+ {
249
258
PyErr_Format (PyExc_TypeError ,
250
- "descriptor '%V ' for '%.100s' objects "
259
+ "descriptor '%.200s ' for '%.100s' objects "
251
260
"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" )) {
255
277
return NULL ;
256
278
}
279
+ return (funcptr )((PyMethodDescrObject * )func )-> d_method -> ml_meth ;
280
+ }
257
281
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 ();
262
303
return result ;
263
304
}
264
305
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 )
270
309
{
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
+ }
274
339
340
+ static PyObject *
341
+ method_vectorcall_FASTCALL (
342
+ PyObject * func , PyObject * const * args , size_t nargsf , PyObject * kwnames )
343
+ {
275
344
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 );
345
+ if (method_check_args (func , args , nargs , kwnames )) {
283
346
return NULL ;
284
347
}
285
- self = args [0 ];
286
- if (!_PyObject_RealIsSubclass ((PyObject * )Py_TYPE (self ),
287
- (PyObject * )PyDescr_TYPE (descr ))) {
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
+ }
357
+
358
+ static PyObject *
359
+ method_vectorcall_FASTCALL_KEYWORDS (
360
+ PyObject * func , PyObject * const * args , size_t nargsf , PyObject * kwnames )
361
+ {
362
+ Py_ssize_t nargs = PyVectorcall_NARGS (nargsf );
363
+ if (method_check_args (func , args , nargs , NULL )) {
364
+ return NULL ;
365
+ }
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 ) {
288
385
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 );
294
387
return NULL ;
295
388
}
389
+ PyCFunction meth = (PyCFunction )method_enter_call (func );
390
+ if (meth == NULL ) {
391
+ return NULL ;
392
+ }
393
+ PyObject * result = meth (args [0 ], NULL );
394
+ Py_LeaveRecursiveCall ();
395
+ return result ;
396
+ }
296
397
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 ();
300
418
return result ;
301
419
}
302
420
421
+
303
422
static PyObject *
304
423
classmethoddescr_call (PyMethodDescrObject * descr , PyObject * args ,
305
424
PyObject * kwds )
@@ -552,7 +671,7 @@ PyTypeObject PyMethodDescr_Type = {
552
671
0 , /* tp_as_sequence */
553
672
0 , /* tp_as_mapping */
554
673
0 , /* tp_hash */
555
- ( ternaryfunc ) methoddescr_call , /* tp_call */
674
+ PyVectorcall_Call , /* tp_call */
556
675
0 , /* tp_str */
557
676
PyObject_GenericGetAttr , /* tp_getattro */
558
677
0 , /* tp_setattro */
@@ -750,13 +869,40 @@ descr_new(PyTypeObject *descrtype, PyTypeObject *type, const char *name)
750
869
PyObject *
751
870
PyDescr_NewMethod (PyTypeObject * type , PyMethodDef * method )
752
871
{
872
+ /* Figure out correct vectorcall function to use */
873
+ vectorcallfunc vectorcall ;
874
+ switch (method -> ml_flags & (METH_VARARGS | METH_FASTCALL | METH_NOARGS | METH_O | METH_KEYWORDS ))
875
+ {
876
+ case METH_VARARGS :
877
+ vectorcall = method_vectorcall_VARARGS ;
878
+ break ;
879
+ case METH_VARARGS | METH_KEYWORDS :
880
+ vectorcall = method_vectorcall_VARARGS_KEYWORDS ;
881
+ break ;
882
+ case METH_FASTCALL :
883
+ vectorcall = method_vectorcall_FASTCALL ;
884
+ break ;
885
+ case METH_FASTCALL | METH_KEYWORDS :
886
+ vectorcall = method_vectorcall_FASTCALL_KEYWORDS ;
887
+ break ;
888
+ case METH_NOARGS :
889
+ vectorcall = method_vectorcall_NOARGS ;
890
+ break ;
891
+ case METH_O :
892
+ vectorcall = method_vectorcall_O ;
893
+ break ;
894
+ default :
895
+ PyErr_SetString (PyExc_SystemError , "bad call flags" );
896
+ return NULL ;
897
+ }
898
+
753
899
PyMethodDescrObject * descr ;
754
900
755
901
descr = (PyMethodDescrObject * )descr_new (& PyMethodDescr_Type ,
756
902
type , method -> ml_name );
757
903
if (descr != NULL ) {
758
904
descr -> d_method = method ;
759
- descr -> vectorcall = _PyMethodDescr_Vectorcall ;
905
+ descr -> vectorcall = vectorcall ;
760
906
}
761
907
return (PyObject * )descr ;
762
908
}
0 commit comments