@@ -19,6 +19,17 @@ static int numfree = 0;
19
19
/* undefine macro trampoline to PyCFunction_NewEx */
20
20
#undef PyCFunction_New
21
21
22
+ /* Forward declarations */
23
+ static inline PyObject * vectorcall_FASTCALL (
24
+ PyObject * func , PyObject * const * args , size_t nargsf , PyObject * kwnames );
25
+ static inline PyObject * vectorcall_FASTCALL_KEYWORDS (
26
+ PyObject * func , PyObject * const * args , size_t nargsf , PyObject * kwnames );
27
+ static inline PyObject * vectorcall_NOARGS (
28
+ PyObject * func , PyObject * const * args , size_t nargsf , PyObject * kwnames );
29
+ static inline PyObject * vectorcall_O (
30
+ PyObject * func , PyObject * const * args , size_t nargsf , PyObject * kwnames );
31
+
32
+
22
33
PyObject *
23
34
PyCFunction_New (PyMethodDef * ml , PyObject * self )
24
35
{
@@ -39,16 +50,16 @@ PyCFunction_NewEx(PyMethodDef *ml, PyObject *self, PyObject *module)
39
50
vectorcall = NULL ;
40
51
break ;
41
52
case METH_FASTCALL :
42
- vectorcall = _PyCFunction_Vectorcall_FASTCALL ;
53
+ vectorcall = vectorcall_FASTCALL ;
43
54
break ;
44
55
case METH_FASTCALL | METH_KEYWORDS :
45
- vectorcall = _PyCFunction_Vectorcall_FASTCALL_KEYWORDS ;
56
+ vectorcall = vectorcall_FASTCALL_KEYWORDS ;
46
57
break ;
47
58
case METH_NOARGS :
48
- vectorcall = _PyCFunction_Vectorcall_NOARGS ;
59
+ vectorcall = vectorcall_NOARGS ;
49
60
break ;
50
61
case METH_O :
51
- vectorcall = _PyCFunction_Vectorcall_O ;
62
+ vectorcall = vectorcall_O ;
52
63
break ;
53
64
default :
54
65
PyErr_SetString (PyExc_SystemError , "bad call flags" );
@@ -353,3 +364,130 @@ _PyCFunction_DebugMallocStats(FILE *out)
353
364
"free PyCFunctionObject" ,
354
365
numfree , sizeof (PyCFunctionObject ));
355
366
}
367
+
368
+
369
+ /* Vectorcall functions for each of the PyCFunction calling conventions,
370
+ * except for METH_VARARGS (possibly combined with METH_KEYWORDS) which
371
+ * doesn't use vectorcall.
372
+ *
373
+ * First, common helpers
374
+ */
375
+ static inline PyObject *
376
+ get_self (PyObject * func ) {
377
+ return ((PyCFunctionObject * )func )-> m_self ;
378
+ }
379
+
380
+ static inline const char *
381
+ get_name (PyObject * func ) {
382
+ PyMethodDef * method = ((PyCFunctionObject * )func )-> m_ml ;
383
+ return method -> ml_name ;
384
+ }
385
+
386
+ typedef void (* funcptr )(void );
387
+
388
+ static inline funcptr
389
+ get_meth (PyObject * func ) {
390
+ PyMethodDef * method = ((PyCFunctionObject * )func )-> m_ml ;
391
+ return (funcptr )method -> ml_meth ;
392
+ }
393
+
394
+ static inline int
395
+ check_no_kwargs (PyObject * func , PyObject * kwnames ) {
396
+ assert (PyCFunction_Check (func ));
397
+ if (kwnames && PyTuple_GET_SIZE (kwnames ) > 0 ) {
398
+ PyErr_Format (PyExc_TypeError ,
399
+ "%.200s() takes no keyword arguments" , get_name (func ));
400
+ return 0 ;
401
+ }
402
+ return 1 ;
403
+ }
404
+
405
+ static inline int
406
+ vectorcall_begin (PyObject * func ) {
407
+ assert (!PyErr_Occurred ());
408
+ assert (PyCFunction_Check (func ));
409
+ if (Py_EnterRecursiveCall (" while calling a Python object" )) {
410
+ return 0 ;
411
+ }
412
+ return 1 ;
413
+ }
414
+
415
+ static inline PyObject *
416
+ vectorcall_end (PyObject * func , PyObject * result ) {
417
+ Py_LeaveRecursiveCall ();
418
+ return _Py_CheckFunctionResult (func , result , NULL );
419
+ }
420
+
421
+
422
+ /* Now the actual vectorcall functions */
423
+ static inline PyObject *
424
+ vectorcall_FASTCALL (
425
+ PyObject * func , PyObject * const * args , size_t nargsf , PyObject * kwnames )
426
+ {
427
+ if (!check_no_kwargs (func , kwnames )) {
428
+ return NULL ;
429
+ }
430
+ if (!vectorcall_begin (func )) {
431
+ return NULL ;
432
+ }
433
+ Py_ssize_t nargs = PyVectorcall_NARGS (nargsf );
434
+ _PyCFunctionFast meth = (_PyCFunctionFast )get_meth (func );
435
+ PyObject * result = meth (get_self (func ), args , nargs );
436
+ return vectorcall_end (func , result );
437
+ }
438
+
439
+ static inline PyObject *
440
+ vectorcall_FASTCALL_KEYWORDS (
441
+ PyObject * func , PyObject * const * args , size_t nargsf , PyObject * kwnames )
442
+ {
443
+ if (!vectorcall_begin (func )) {
444
+ return NULL ;
445
+ }
446
+ Py_ssize_t nargs = PyVectorcall_NARGS (nargsf );
447
+ _PyCFunctionFastWithKeywords meth = (_PyCFunctionFastWithKeywords )get_meth (func );
448
+ PyObject * result = meth (get_self (func ), args , nargs , kwnames );
449
+ return vectorcall_end (func , result );
450
+ }
451
+
452
+ static inline PyObject *
453
+ vectorcall_NOARGS (
454
+ PyObject * func , PyObject * const * args , size_t nargsf , PyObject * kwnames )
455
+ {
456
+ if (!check_no_kwargs (func , kwnames )) {
457
+ return NULL ;
458
+ }
459
+ Py_ssize_t nargs = PyVectorcall_NARGS (nargsf );
460
+ if (nargs != 0 ) {
461
+ PyErr_Format (PyExc_TypeError ,
462
+ "%.200s() takes no arguments (%zd given)" , get_name (func ), nargs );
463
+ return NULL ;
464
+ }
465
+ if (!vectorcall_begin (func )) {
466
+ return NULL ;
467
+ }
468
+ PyCFunction meth = (PyCFunction )get_meth (func );
469
+ PyObject * result = meth (get_self (func ), NULL );
470
+ return vectorcall_end (func , result );
471
+ }
472
+
473
+ static inline PyObject *
474
+ vectorcall_O (
475
+ PyObject * func , PyObject * const * args , size_t nargsf , PyObject * kwnames )
476
+ {
477
+ if (!check_no_kwargs (func , kwnames )) {
478
+ return NULL ;
479
+ }
480
+ Py_ssize_t nargs = PyVectorcall_NARGS (nargsf );
481
+ if (nargs != 1 ) {
482
+ PyErr_Format (PyExc_TypeError ,
483
+ "%.200s() takes exactly one argument (%zd given)" ,
484
+ get_name (func ), nargs );
485
+ return NULL ;
486
+ }
487
+ if (!vectorcall_begin (func )) {
488
+ return NULL ;
489
+ }
490
+ PyCFunction meth = (PyCFunction )get_meth (func );
491
+ PyObject * result = meth (get_self (func ), args [0 ]);
492
+ return vectorcall_end (func , result );
493
+ }
0 commit comments