Skip to content

Commit 54e4e69

Browse files
encukoujdemeyer
authored andcommitted
Break up the long macro in descrobject.c
1 parent d942285 commit 54e4e69

File tree

1 file changed

+143
-78
lines changed

1 file changed

+143
-78
lines changed

Objects/descrobject.c

Lines changed: 143 additions & 78 deletions
Original file line numberDiff line numberDiff line change
@@ -229,145 +229,210 @@ getset_set(PyGetSetDescrObject *descr, PyObject *obj, PyObject *value)
229229

230230
/* Vectorcall functions for each of the PyMethodDescr calling conventions.
231231
*
232-
* First two macros to define common boilerplate
232+
* First, common helpers
233233
*/
234-
#define PyMethodDescr_VECTORCALL_BEGIN(ALLOW_KWARGS) \
235-
assert(!PyErr_Occurred()); \
236-
assert(PyObject_TypeCheck(func, &PyMethodDescr_Type)); \
237-
PyMethodDescrObject *f = (PyMethodDescrObject *)func; \
238-
Py_ssize_t nargs = PyVectorcall_NARGS(nargsf); \
239-
PyMethodDef *method = f->d_method; \
240-
const char *name = method->ml_name; \
241-
void(*meth)(void) = (void(*)(void))method->ml_meth; \
242-
PyObject *result = NULL; \
243-
\
244-
/* self is the first positional argument */ \
245-
if (nargs < 1) { \
246-
PyErr_Format(PyExc_TypeError, \
247-
"descriptor '%.200s' of '%.100s' " \
248-
"object needs an argument", \
249-
name, PyDescr_TYPE(func)->tp_name); \
250-
return NULL; \
251-
} \
252-
PyObject *self = args[0]; \
253-
args++; \
254-
nargs--; \
255-
if (!_PyObject_RealIsSubclass((PyObject *)Py_TYPE(self), \
256-
(PyObject *)PyDescr_TYPE(func))) \
257-
{ \
258-
PyErr_Format(PyExc_TypeError, \
259-
"descriptor '%.200s' for '%.100s' objects " \
260-
"doesn't apply to a '%.100s' object", \
261-
name, PyDescr_TYPE(func)->tp_name, \
262-
Py_TYPE(self)->tp_name); \
263-
return NULL; \
264-
} \
265-
\
266-
if (!ALLOW_KWARGS && kwnames && PyTuple_GET_SIZE(kwnames) > 0) { \
267-
PyErr_Format(PyExc_TypeError, \
268-
"%.200s() takes no keyword arguments", name); \
269-
return NULL; \
270-
} \
271-
if (Py_EnterRecursiveCall(" while calling a Python object")) { \
272-
return NULL; \
273-
}
274-
275-
#define PyMethodDescr_VECTORCALL_END \
276-
Py_LeaveRecursiveCall(); \
234+
static inline const char *
235+
get_name(PyObject *func) {
236+
return ((PyMethodDescrObject *)func)->d_method->ml_name;
237+
}
238+
239+
typedef void (*funcptr)(void);
240+
241+
static inline funcptr
242+
get_meth(PyObject *func) {
243+
PyMethodDef *method = ((PyMethodDescrObject *)func)->d_method;
244+
return (funcptr)method->ml_meth;
245+
}
246+
247+
static inline int
248+
vectorcall_check(PyObject *func, size_t nargs, PyObject *const *args) {
249+
assert(!PyErr_Occurred());
250+
assert(PyObject_TypeCheck(func, &PyMethodDescr_Type));
251+
if (nargs < 1) {
252+
PyErr_Format(PyExc_TypeError,
253+
"descriptor '%.200s' of '%.100s' "
254+
"object needs an argument",
255+
get_name(func), PyDescr_TYPE(func)->tp_name);
256+
return 0;
257+
}
258+
PyObject *self = args[0];
259+
if (!_PyObject_RealIsSubclass((PyObject *)Py_TYPE(self),
260+
(PyObject *)PyDescr_TYPE(func)))
261+
{
262+
PyErr_Format(PyExc_TypeError,
263+
"descriptor '%.200s' for '%.100s' objects "
264+
"doesn't apply to a '%.100s' object",
265+
get_name(func), PyDescr_TYPE(func)->tp_name,
266+
Py_TYPE(self)->tp_name);
267+
return 0;
268+
}
269+
return 1;
270+
}
271+
272+
static inline int
273+
check_no_kwargs(PyObject *func, PyObject *kwnames) {
274+
if (kwnames && PyTuple_GET_SIZE(kwnames) > 0) {
275+
PyErr_Format(PyExc_TypeError,
276+
"%.200s() takes no keyword arguments", get_name(func));
277+
return 0;
278+
}
279+
return 1;
280+
}
281+
282+
static inline int
283+
vectorcall_begin() {
284+
if (Py_EnterRecursiveCall(" while calling a Python object")) {
285+
return 0;
286+
}
287+
return 1;
288+
}
289+
290+
static inline PyObject *
291+
vectorcall_end(PyObject *func, PyObject *result) {
292+
Py_LeaveRecursiveCall();
277293
return _Py_CheckFunctionResult(func, result, NULL);
294+
}
278295

279296
/* Now the actual vectorcall functions */
280297
static PyObject *
281298
_PyMethodDescr_Vectorcall_VARARGS(
282299
PyObject *func, PyObject *const *args, size_t nargsf, PyObject *kwnames)
283300
{
284-
PyMethodDescr_VECTORCALL_BEGIN(0)
285-
/* Create a temporary tuple for positional arguments */
286-
PyObject *argstuple = _PyTuple_FromArray(args, nargs);
301+
Py_ssize_t nargs = PyVectorcall_NARGS(nargsf);
302+
if (!vectorcall_check(func, nargs, args)) {
303+
return NULL;
304+
}
305+
if (!check_no_kwargs(func, kwnames)) {
306+
return NULL;
307+
}
308+
PyObject *argstuple = _PyTuple_FromArray(args+1, nargs-1);
287309
if (argstuple == NULL) {
288-
goto exit;
310+
return NULL;
311+
}
312+
if (!vectorcall_begin()) {
313+
return NULL;
289314
}
290-
result = ((PyCFunction)meth)(self, argstuple);
315+
PyCFunction meth = (PyCFunction)get_meth(func);
316+
PyObject *result = meth(args[0], argstuple);
291317
Py_DECREF(argstuple);
292-
exit:
293-
PyMethodDescr_VECTORCALL_END
318+
return vectorcall_end(func, result);
294319
}
295320

296321
static PyObject *
297322
_PyMethodDescr_Vectorcall_VARARGS_KEYWORDS(
298323
PyObject *func, PyObject *const *args, size_t nargsf, PyObject *kwnames)
299324
{
300-
PyMethodDescr_VECTORCALL_BEGIN(1)
301-
/* Create a temporary tuple for positional arguments */
302-
PyObject *argstuple = _PyTuple_FromArray(args, nargs);
325+
Py_ssize_t nargs = PyVectorcall_NARGS(nargsf);
326+
if (!vectorcall_check(func, nargs, args)) {
327+
return NULL;
328+
}
329+
PyObject *argstuple = _PyTuple_FromArray(args+1, nargs-1);
303330
if (argstuple == NULL) {
304-
goto exit;
331+
return NULL;
305332
}
333+
PyObject *result = NULL;
306334
/* Create a temporary dict for keyword arguments */
307335
PyObject *kwdict;
308336
if (kwnames == NULL || PyTuple_GET_SIZE(kwnames) == 0) {
309337
kwdict = NULL;
310338
}
311339
else {
312-
kwdict = _PyStack_AsDict(args + nargs, kwnames);
340+
kwdict = _PyStack_AsDict(args+1 + nargs, kwnames);
313341
if (kwdict == NULL) {
314342
Py_DECREF(argstuple);
315-
goto exit;
343+
return NULL;
316344
}
317345
}
318-
result = ((PyCFunctionWithKeywords)meth)(self, argstuple, kwdict);
346+
if (!vectorcall_begin()) {
347+
return NULL;
348+
}
349+
PyCFunctionWithKeywords meth = (PyCFunctionWithKeywords)get_meth(func);
350+
result = meth(args[0], argstuple, kwdict);
319351
Py_DECREF(argstuple);
320352
Py_XDECREF(kwdict);
321-
exit:
322-
PyMethodDescr_VECTORCALL_END
353+
return vectorcall_end(func, result);
323354
}
324355

325356
static PyObject *
326357
_PyMethodDescr_Vectorcall_FASTCALL(
327358
PyObject *func, PyObject *const *args, size_t nargsf, PyObject *kwnames)
328359
{
329-
PyMethodDescr_VECTORCALL_BEGIN(0)
330-
result = ((_PyCFunctionFast)meth)(self, args, nargs);
331-
PyMethodDescr_VECTORCALL_END
360+
Py_ssize_t nargs = PyVectorcall_NARGS(nargsf);
361+
if (!vectorcall_check(func, nargs, args)) {
362+
return NULL;
363+
}
364+
if (!check_no_kwargs(func, kwnames)) {
365+
return NULL;
366+
}
367+
if (!vectorcall_begin()) {
368+
return NULL;
369+
}
370+
_PyCFunctionFast meth = (_PyCFunctionFast)get_meth(func);
371+
PyObject *result = meth(args[0], args+1, nargs-1);
372+
return vectorcall_end(func, result);
332373
}
333374

334375
static PyObject *
335376
_PyMethodDescr_Vectorcall_FASTCALL_KEYWORDS(
336377
PyObject *func, PyObject *const *args, size_t nargsf, PyObject *kwnames)
337378
{
338-
PyMethodDescr_VECTORCALL_BEGIN(1)
339-
result = ((_PyCFunctionFastWithKeywords)meth)(self, args, nargs, kwnames);
340-
PyMethodDescr_VECTORCALL_END
379+
Py_ssize_t nargs = PyVectorcall_NARGS(nargsf);
380+
if (!vectorcall_check(func, nargs, args)) {
381+
return NULL;
382+
}
383+
vectorcall_begin();
384+
_PyCFunctionFastWithKeywords meth = (_PyCFunctionFastWithKeywords)get_meth(func);
385+
PyObject *result = meth(args[0], args+1, nargs-1, kwnames);
386+
return vectorcall_end(func, result);
341387
}
342388

343389
static PyObject *
344390
_PyMethodDescr_Vectorcall_NOARGS(
345391
PyObject *func, PyObject *const *args, size_t nargsf, PyObject *kwnames)
346392
{
347-
PyMethodDescr_VECTORCALL_BEGIN(0)
348-
if (nargs != 0) {
393+
Py_ssize_t nargs = PyVectorcall_NARGS(nargsf);
394+
if (!vectorcall_check(func, nargs, args)) {
395+
return NULL;
396+
}
397+
if (!check_no_kwargs(func, kwnames)) {
398+
return NULL;
399+
}
400+
if (nargs != 1) {
349401
PyErr_Format(PyExc_TypeError,
350-
"%.200s() takes no arguments (%zd given)", name, nargs);
402+
"%.200s() takes no arguments (%zd given)", get_name(func), nargs-1);
403+
return NULL;
351404
}
352-
else {
353-
result = ((PyCFunction)meth)(self, NULL);
405+
if (!vectorcall_begin()) {
406+
return NULL;
354407
}
355-
PyMethodDescr_VECTORCALL_END
408+
PyCFunction meth = (PyCFunction)get_meth(func);
409+
PyObject *result = meth(args[0], NULL);
410+
return vectorcall_end(func, result);
356411
}
357412

358413
static PyObject *
359414
_PyMethodDescr_Vectorcall_O(
360415
PyObject *func, PyObject *const *args, size_t nargsf, PyObject *kwnames)
361416
{
362-
PyMethodDescr_VECTORCALL_BEGIN(0)
363-
if (nargs != 1) {
417+
Py_ssize_t nargs = PyVectorcall_NARGS(nargsf);
418+
if (!vectorcall_check(func, nargs, args)) {
419+
return NULL;
420+
}
421+
if (!check_no_kwargs(func, kwnames)) {
422+
return NULL;
423+
}
424+
if (nargs != 2) {
364425
PyErr_Format(PyExc_TypeError,
365-
"%.200s() takes exactly one argument (%zd given)", name, nargs);
426+
"%.200s() takes exactly one argument (%zd given)",
427+
get_name(func), nargs-1);
428+
return NULL;
366429
}
367-
else {
368-
result = ((PyCFunction)meth)(self, args[0]);
430+
if (!vectorcall_begin()) {
431+
return NULL;
369432
}
370-
PyMethodDescr_VECTORCALL_END
433+
PyCFunction meth = (PyCFunction)get_meth(func);
434+
PyObject *result = meth(args[0], args[1]);
435+
return vectorcall_end(func, result);
371436
}
372437

373438

0 commit comments

Comments
 (0)