Skip to content

Commit d942285

Browse files
encukoujdemeyer
authored andcommitted
Make PyCFunction vectorcall truly private and break up big macro
1 parent dc7680e commit d942285

File tree

4 files changed

+143
-97
lines changed

4 files changed

+143
-97
lines changed

Include/methodobject.h

Lines changed: 0 additions & 11 deletions
Original file line numberDiff line numberDiff line change
@@ -41,17 +41,6 @@ PyAPI_FUNC(int) PyCFunction_GetFlags(PyObject *);
4141
#endif
4242
PyAPI_FUNC(PyObject *) PyCFunction_Call(PyObject *, PyObject *, PyObject *);
4343

44-
#ifdef Py_BUILD_CORE
45-
extern PyObject * _PyCFunction_Vectorcall_FASTCALL(
46-
PyObject *func, PyObject *const *args, size_t nargsf, PyObject *kwnames);
47-
extern PyObject * _PyCFunction_Vectorcall_FASTCALL_KEYWORDS(
48-
PyObject *func, PyObject *const *args, size_t nargsf, PyObject *kwnames);
49-
extern PyObject * _PyCFunction_Vectorcall_NOARGS(
50-
PyObject *func, PyObject *const *args, size_t nargsf, PyObject *kwnames);
51-
extern PyObject * _PyCFunction_Vectorcall_O(
52-
PyObject *func, PyObject *const *args, size_t nargsf, PyObject *kwnames);
53-
#endif
54-
5544
struct PyMethodDef {
5645
const char *ml_name; /* The name of the built-in function/method */
5746
PyCFunction ml_meth; /* The C function that implements it */

Objects/call.c

Lines changed: 0 additions & 81 deletions
Original file line numberDiff line numberDiff line change
@@ -625,87 +625,6 @@ _PyMethodDef_RawFastCallKeywords(PyMethodDef *method, PyObject *self,
625625
return result;
626626
}
627627

628-
629-
/* Vectorcall functions for each of the PyCFunction calling conventions,
630-
* except for METH_VARARGS (possibly combined with METH_KEYWORDS) which
631-
* doesn't use vectorcall.
632-
*
633-
* First two macros to define common boilerplate
634-
*/
635-
#define PyCFunction_VECTORCALL_BEGIN(ALLOW_KWARGS) \
636-
assert(!PyErr_Occurred()); \
637-
assert(PyCFunction_Check(func)); \
638-
PyCFunctionObject *f = (PyCFunctionObject *)func; \
639-
Py_ssize_t nargs = PyVectorcall_NARGS(nargsf); \
640-
PyObject *self = f->m_self; \
641-
PyMethodDef *method = f->m_ml; \
642-
const char *name = method->ml_name; \
643-
void(*meth)(void) = (void(*)(void))method->ml_meth; \
644-
PyObject *result = NULL; \
645-
\
646-
if (!ALLOW_KWARGS && kwnames && PyTuple_GET_SIZE(kwnames) > 0) { \
647-
PyErr_Format(PyExc_TypeError, \
648-
"%.200s() takes no keyword arguments", name); \
649-
return NULL; \
650-
} \
651-
if (Py_EnterRecursiveCall(" while calling a Python object")) { \
652-
return NULL; \
653-
}
654-
655-
#define PyCFunction_VECTORCALL_END \
656-
Py_LeaveRecursiveCall(); \
657-
return _Py_CheckFunctionResult(func, result, NULL);
658-
659-
/* Now the actual vectorcall functions */
660-
PyObject *
661-
_PyCFunction_Vectorcall_FASTCALL(
662-
PyObject *func, PyObject *const *args, size_t nargsf, PyObject *kwnames)
663-
{
664-
PyCFunction_VECTORCALL_BEGIN(0)
665-
result = ((_PyCFunctionFast)meth)(self, args, nargs);
666-
PyCFunction_VECTORCALL_END
667-
}
668-
669-
PyObject *
670-
_PyCFunction_Vectorcall_FASTCALL_KEYWORDS(
671-
PyObject *func, PyObject *const *args, size_t nargsf, PyObject *kwnames)
672-
{
673-
PyCFunction_VECTORCALL_BEGIN(1)
674-
result = ((_PyCFunctionFastWithKeywords)meth)(self, args, nargs, kwnames);
675-
PyCFunction_VECTORCALL_END
676-
}
677-
678-
PyObject *
679-
_PyCFunction_Vectorcall_NOARGS(
680-
PyObject *func, PyObject *const *args, size_t nargsf, PyObject *kwnames)
681-
{
682-
PyCFunction_VECTORCALL_BEGIN(0)
683-
if (nargs != 0) {
684-
PyErr_Format(PyExc_TypeError,
685-
"%.200s() takes no arguments (%zd given)", name, nargs);
686-
}
687-
else {
688-
result = ((PyCFunction)meth)(self, NULL);
689-
}
690-
PyCFunction_VECTORCALL_END
691-
}
692-
693-
PyObject *
694-
_PyCFunction_Vectorcall_O(
695-
PyObject *func, PyObject *const *args, size_t nargsf, PyObject *kwnames)
696-
{
697-
PyCFunction_VECTORCALL_BEGIN(0)
698-
if (nargs != 1) {
699-
PyErr_Format(PyExc_TypeError,
700-
"%.200s() takes exactly one argument (%zd given)", name, nargs);
701-
}
702-
else {
703-
result = ((PyCFunction)meth)(self, args[0]);
704-
}
705-
PyCFunction_VECTORCALL_END
706-
}
707-
708-
709628
static PyObject *
710629
cfunction_call_varargs(PyObject *func, PyObject *args, PyObject *kwargs)
711630
{

Objects/methodobject.c

Lines changed: 142 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -19,6 +19,17 @@ static int numfree = 0;
1919
/* undefine macro trampoline to PyCFunction_NewEx */
2020
#undef PyCFunction_New
2121

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+
2233
PyObject *
2334
PyCFunction_New(PyMethodDef *ml, PyObject *self)
2435
{
@@ -39,16 +50,16 @@ PyCFunction_NewEx(PyMethodDef *ml, PyObject *self, PyObject *module)
3950
vectorcall = NULL;
4051
break;
4152
case METH_FASTCALL:
42-
vectorcall = _PyCFunction_Vectorcall_FASTCALL;
53+
vectorcall = vectorcall_FASTCALL;
4354
break;
4455
case METH_FASTCALL | METH_KEYWORDS:
45-
vectorcall = _PyCFunction_Vectorcall_FASTCALL_KEYWORDS;
56+
vectorcall = vectorcall_FASTCALL_KEYWORDS;
4657
break;
4758
case METH_NOARGS:
48-
vectorcall = _PyCFunction_Vectorcall_NOARGS;
59+
vectorcall = vectorcall_NOARGS;
4960
break;
5061
case METH_O:
51-
vectorcall = _PyCFunction_Vectorcall_O;
62+
vectorcall = vectorcall_O;
5263
break;
5364
default:
5465
PyErr_SetString(PyExc_SystemError, "bad call flags");
@@ -353,3 +364,130 @@ _PyCFunction_DebugMallocStats(FILE *out)
353364
"free PyCFunctionObject",
354365
numfree, sizeof(PyCFunctionObject));
355366
}
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+
}

Tools/gdb/libpython.py

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1563,7 +1563,7 @@ def is_other_python_frame(self):
15631563
if not caller:
15641564
return False
15651565

1566-
if (caller.startswith('_PyCFunction_Vectorcall') or
1566+
if (caller.startswith('vectorcall_') or
15671567
caller == 'cfunction_call_varargs'):
15681568
arg_name = 'func'
15691569
# Within that frame:

0 commit comments

Comments
 (0)