@@ -227,86 +227,199 @@ getset_set(PyGetSetDescrObject *descr, PyObject *obj, PyObject *value)
227
227
return -1 ;
228
228
}
229
229
230
- static PyObject *
231
- methoddescr_call (PyMethodDescrObject * descr , PyObject * args , PyObject * kwargs )
232
- {
233
- STACKLESS_GETARG ();
234
- Py_ssize_t nargs ;
235
- PyObject * self , * result ;
236
230
237
- /* Make sure that the first argument is acceptable as 'self' */
238
- assert (PyTuple_Check (args ));
239
- nargs = PyTuple_GET_SIZE (args );
231
+ /* Vectorcall functions for each of the PyMethodDescr calling conventions.
232
+ *
233
+ * First, common helpers
234
+ */
235
+ static const char *
236
+ get_name (PyObject * func ) {
237
+ assert (PyObject_TypeCheck (func , & PyMethodDescr_Type ));
238
+ return ((PyMethodDescrObject * )func )-> d_method -> ml_name ;
239
+ }
240
+
241
+ typedef void (* funcptr )(void );
242
+
243
+ static inline int
244
+ method_check_args (PyObject * func , PyObject * const * args , Py_ssize_t nargs , PyObject * kwnames )
245
+ {
246
+ assert (!PyErr_Occurred ());
247
+ assert (PyObject_TypeCheck (func , & PyMethodDescr_Type ));
240
248
if (nargs < 1 ) {
241
249
PyErr_Format (PyExc_TypeError ,
242
- "descriptor '%V ' of '%.100s' "
250
+ "descriptor '%.200s ' of '%.100s' "
243
251
"object needs an argument" ,
244
- descr_name ((PyDescrObject * )descr ), "?" ,
245
- PyDescr_TYPE (descr )-> tp_name );
246
- return NULL ;
252
+ get_name (func ), PyDescr_TYPE (func )-> tp_name );
253
+ return -1 ;
247
254
}
248
- self = PyTuple_GET_ITEM ( args , 0 ) ;
255
+ PyObject * self = args [ 0 ] ;
249
256
if (!_PyObject_RealIsSubclass ((PyObject * )Py_TYPE (self ),
250
- (PyObject * )PyDescr_TYPE (descr ))) {
257
+ (PyObject * )PyDescr_TYPE (func )))
258
+ {
251
259
PyErr_Format (PyExc_TypeError ,
252
- "descriptor '%V ' for '%.100s' objects "
260
+ "descriptor '%.200s ' for '%.100s' objects "
253
261
"doesn't apply to a '%.100s' object" ,
254
- descr_name ((PyDescrObject * )descr ), "?" ,
255
- PyDescr_TYPE (descr )-> tp_name ,
256
- self -> ob_type -> tp_name );
262
+ get_name (func ), PyDescr_TYPE (func )-> tp_name ,
263
+ Py_TYPE (self )-> tp_name );
264
+ return -1 ;
265
+ }
266
+ if (kwnames && PyTuple_GET_SIZE (kwnames )) {
267
+ PyErr_Format (PyExc_TypeError ,
268
+ "%.200s() takes no keyword arguments" , get_name (func ));
269
+ return -1 ;
270
+ }
271
+ return 0 ;
272
+ }
273
+
274
+ static inline funcptr
275
+ method_enter_call (PyObject * func )
276
+ {
277
+ if (Py_EnterRecursiveCall (" while calling a Python object" )) {
257
278
return NULL ;
258
279
}
280
+ return (funcptr )((PyMethodDescrObject * )func )-> d_method -> ml_meth ;
281
+ }
259
282
260
- STACKLESS_PROMOTE_ALL ();
261
- result = _PyMethodDef_RawFastCallDict (descr -> d_method , self ,
262
- & _PyTuple_ITEMS (args )[1 ], nargs - 1 ,
263
- kwargs );
264
- STACKLESS_ASSERT ();
265
- result = _Py_CheckFunctionResult ((PyObject * )descr , result , NULL );
283
+ /* Now the actual vectorcall functions */
284
+ static PyObject *
285
+ method_vectorcall_VARARGS (
286
+ PyObject * func , PyObject * const * args , size_t nargsf , PyObject * kwnames )
287
+ {
288
+ Py_ssize_t nargs = PyVectorcall_NARGS (nargsf );
289
+ if (method_check_args (func , args , nargs , kwnames )) {
290
+ return NULL ;
291
+ }
292
+ PyObject * argstuple = _PyTuple_FromArray (args + 1 , nargs - 1 );
293
+ if (argstuple == NULL ) {
294
+ return NULL ;
295
+ }
296
+ PyCFunction meth = (PyCFunction )method_enter_call (func );
297
+ if (meth == NULL ) {
298
+ Py_DECREF (argstuple );
299
+ return NULL ;
300
+ }
301
+ PyObject * result = meth (args [0 ], argstuple );
302
+ Py_DECREF (argstuple );
303
+ Py_LeaveRecursiveCall ();
266
304
return result ;
267
305
}
268
306
269
- // same to methoddescr_call(), but use FASTCALL convention.
270
- PyObject *
271
- _PyMethodDescr_Vectorcall (PyObject * descrobj ,
272
- PyObject * const * args , size_t nargsf ,
273
- PyObject * kwnames )
307
+ static PyObject *
308
+ method_vectorcall_VARARGS_KEYWORDS (
309
+ PyObject * func , PyObject * const * args , size_t nargsf , PyObject * kwnames )
274
310
{
275
- STACKLESS_VECTORCALL_GETARG (_PyMethodDescr_Vectorcall );
276
- assert (Py_TYPE (descrobj ) == & PyMethodDescr_Type );
277
- PyMethodDescrObject * descr = (PyMethodDescrObject * )descrobj ;
278
- PyObject * self , * result ;
311
+ Py_ssize_t nargs = PyVectorcall_NARGS (nargsf );
312
+ if (method_check_args (func , args , nargs , NULL )) {
313
+ return NULL ;
314
+ }
315
+ PyObject * argstuple = _PyTuple_FromArray (args + 1 , nargs - 1 );
316
+ if (argstuple == NULL ) {
317
+ return NULL ;
318
+ }
319
+ PyObject * result = NULL ;
320
+ /* Create a temporary dict for keyword arguments */
321
+ PyObject * kwdict = NULL ;
322
+ if (kwnames != NULL && PyTuple_GET_SIZE (kwnames ) > 0 ) {
323
+ kwdict = _PyStack_AsDict (args + nargs , kwnames );
324
+ if (kwdict == NULL ) {
325
+ goto exit ;
326
+ }
327
+ }
328
+ PyCFunctionWithKeywords meth = (PyCFunctionWithKeywords )
329
+ method_enter_call (func );
330
+ if (meth == NULL ) {
331
+ goto exit ;
332
+ }
333
+ result = meth (args [0 ], argstuple , kwdict );
334
+ Py_LeaveRecursiveCall ();
335
+ exit :
336
+ Py_DECREF (argstuple );
337
+ Py_XDECREF (kwdict );
338
+ return result ;
339
+ }
279
340
341
+ static PyObject *
342
+ method_vectorcall_FASTCALL (
343
+ PyObject * func , PyObject * const * args , size_t nargsf , PyObject * kwnames )
344
+ {
280
345
Py_ssize_t nargs = PyVectorcall_NARGS (nargsf );
281
- /* Make sure that the first argument is acceptable as 'self' */
282
- if (nargs < 1 ) {
283
- PyErr_Format (PyExc_TypeError ,
284
- "descriptor '%V' of '%.100s' "
285
- "object needs an argument" ,
286
- descr_name ((PyDescrObject * )descr ), "?" ,
287
- PyDescr_TYPE (descr )-> tp_name );
346
+ if (method_check_args (func , args , nargs , kwnames )) {
288
347
return NULL ;
289
348
}
290
- self = args [0 ];
291
- if (!_PyObject_RealIsSubclass ((PyObject * )Py_TYPE (self ),
292
- (PyObject * )PyDescr_TYPE (descr ))) {
349
+ _PyCFunctionFast meth = (_PyCFunctionFast )
350
+ method_enter_call (func );
351
+ if (meth == NULL ) {
352
+ return NULL ;
353
+ }
354
+ PyObject * result = meth (args [0 ], args + 1 , nargs - 1 );
355
+ Py_LeaveRecursiveCall ();
356
+ return result ;
357
+ }
358
+
359
+ static PyObject *
360
+ method_vectorcall_FASTCALL_KEYWORDS (
361
+ PyObject * func , PyObject * const * args , size_t nargsf , PyObject * kwnames )
362
+ {
363
+ Py_ssize_t nargs = PyVectorcall_NARGS (nargsf );
364
+ if (method_check_args (func , args , nargs , NULL )) {
365
+ return NULL ;
366
+ }
367
+ _PyCFunctionFastWithKeywords meth = (_PyCFunctionFastWithKeywords )
368
+ method_enter_call (func );
369
+ if (meth == NULL ) {
370
+ return NULL ;
371
+ }
372
+ PyObject * result = meth (args [0 ], args + 1 , nargs - 1 , kwnames );
373
+ Py_LeaveRecursiveCall ();
374
+ return result ;
375
+ }
376
+
377
+ static PyObject *
378
+ method_vectorcall_NOARGS (
379
+ PyObject * func , PyObject * const * args , size_t nargsf , PyObject * kwnames )
380
+ {
381
+ Py_ssize_t nargs = PyVectorcall_NARGS (nargsf );
382
+ if (method_check_args (func , args , nargs , kwnames )) {
383
+ return NULL ;
384
+ }
385
+ if (nargs != 1 ) {
293
386
PyErr_Format (PyExc_TypeError ,
294
- "descriptor '%V' for '%.100s' objects "
295
- "doesn't apply to a '%.100s' object" ,
296
- descr_name ((PyDescrObject * )descr ), "?" ,
297
- PyDescr_TYPE (descr )-> tp_name ,
298
- self -> ob_type -> tp_name );
387
+ "%.200s() takes no arguments (%zd given)" , get_name (func ), nargs - 1 );
299
388
return NULL ;
300
389
}
390
+ PyCFunction meth = (PyCFunction )method_enter_call (func );
391
+ if (meth == NULL ) {
392
+ return NULL ;
393
+ }
394
+ PyObject * result = meth (args [0 ], NULL );
395
+ Py_LeaveRecursiveCall ();
396
+ return result ;
397
+ }
301
398
302
- STACKLESS_PROMOTE_ALL ();
303
- result = _PyMethodDef_RawFastCallKeywords (descr -> d_method , self ,
304
- args + 1 , nargs - 1 , kwnames );
305
- STACKLESS_ASSERT ();
306
- result = _Py_CheckFunctionResult ((PyObject * )descr , result , NULL );
399
+ static PyObject *
400
+ method_vectorcall_O (
401
+ PyObject * func , PyObject * const * args , size_t nargsf , PyObject * kwnames )
402
+ {
403
+ Py_ssize_t nargs = PyVectorcall_NARGS (nargsf );
404
+ if (method_check_args (func , args , nargs , kwnames )) {
405
+ return NULL ;
406
+ }
407
+ if (nargs != 2 ) {
408
+ PyErr_Format (PyExc_TypeError ,
409
+ "%.200s() takes exactly one argument (%zd given)" ,
410
+ get_name (func ), nargs - 1 );
411
+ return NULL ;
412
+ }
413
+ PyCFunction meth = (PyCFunction )method_enter_call (func );
414
+ if (meth == NULL ) {
415
+ return NULL ;
416
+ }
417
+ PyObject * result = meth (args [0 ], args [1 ]);
418
+ Py_LeaveRecursiveCall ();
307
419
return result ;
308
420
}
309
421
422
+
310
423
static PyObject *
311
424
classmethoddescr_call (PyMethodDescrObject * descr , PyObject * args ,
312
425
PyObject * kwds )
@@ -579,7 +692,7 @@ PyTypeObject PyMethodDescr_Type = {
579
692
0 , /* tp_as_sequence */
580
693
SLP_TP_AS_MAPPING (descr_as_mapping ), /* tp_as_mapping */
581
694
0 , /* tp_hash */
582
- ( ternaryfunc ) methoddescr_call , /* tp_call */
695
+ PyVectorcall_Call , /* tp_call */
583
696
0 , /* tp_str */
584
697
PyObject_GenericGetAttr , /* tp_getattro */
585
698
0 , /* tp_setattro */
@@ -783,13 +896,40 @@ descr_new(PyTypeObject *descrtype, PyTypeObject *type, const char *name)
783
896
PyObject *
784
897
PyDescr_NewMethod (PyTypeObject * type , PyMethodDef * method )
785
898
{
899
+ /* Figure out correct vectorcall function to use */
900
+ vectorcallfunc vectorcall ;
901
+ switch (method -> ml_flags & (METH_VARARGS | METH_FASTCALL | METH_NOARGS | METH_O | METH_KEYWORDS ))
902
+ {
903
+ case METH_VARARGS :
904
+ vectorcall = method_vectorcall_VARARGS ;
905
+ break ;
906
+ case METH_VARARGS | METH_KEYWORDS :
907
+ vectorcall = method_vectorcall_VARARGS_KEYWORDS ;
908
+ break ;
909
+ case METH_FASTCALL :
910
+ vectorcall = method_vectorcall_FASTCALL ;
911
+ break ;
912
+ case METH_FASTCALL | METH_KEYWORDS :
913
+ vectorcall = method_vectorcall_FASTCALL_KEYWORDS ;
914
+ break ;
915
+ case METH_NOARGS :
916
+ vectorcall = method_vectorcall_NOARGS ;
917
+ break ;
918
+ case METH_O :
919
+ vectorcall = method_vectorcall_O ;
920
+ break ;
921
+ default :
922
+ PyErr_SetString (PyExc_SystemError , "bad call flags" );
923
+ return NULL ;
924
+ }
925
+
786
926
PyMethodDescrObject * descr ;
787
927
788
928
descr = (PyMethodDescrObject * )descr_new (& PyMethodDescr_Type ,
789
929
type , method -> ml_name );
790
930
if (descr != NULL ) {
791
931
descr -> d_method = method ;
792
- descr -> vectorcall = _PyMethodDescr_Vectorcall ;
932
+ descr -> vectorcall = vectorcall ;
793
933
}
794
934
return (PyObject * )descr ;
795
935
}
0 commit comments