Skip to content

Commit b68176d

Browse files
committed
Avoid temporary varargs tuple creation in argument passing
1 parent 196b53e commit b68176d

4 files changed

Lines changed: 55 additions & 55 deletions

File tree

‎Include/modsupport.h‎

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -134,7 +134,8 @@ PyAPI_FUNC(PyObject * const *) _PyArg_UnpackKeywordsWithVararg(
134134
PyObject *kwargs, PyObject *kwnames,
135135
struct _PyArg_Parser *parser,
136136
int minpos, int maxpos, int minkw,
137-
int vararg, PyObject **buf);
137+
int vararg, Py_ssize_t varargssize,
138+
PyObject **buf);
138139

139140
#define _PyArg_UnpackKeywords(args, nargs, kwargs, kwnames, parser, minpos, maxpos, minkw, buf) \
140141
(((minkw) == 0 && (kwargs) == NULL && (kwnames) == NULL && \

‎Lib/test/clinic.test‎

Lines changed: 37 additions & 30 deletions
Original file line numberDiff line numberDiff line change
@@ -3324,14 +3324,15 @@ PyDoc_STRVAR(test_vararg_and_posonly__doc__,
33243324
{"test_vararg_and_posonly", (PyCFunction)(void(*)(void))test_vararg_and_posonly, METH_FASTCALL, test_vararg_and_posonly__doc__},
33253325

33263326
static PyObject *
3327-
test_vararg_and_posonly_impl(PyObject *module, PyObject *a, PyObject *args);
3327+
test_vararg_and_posonly_impl(PyObject *module, PyObject *a,
3328+
Py_ssize_t varargssize, PyObject *const *args);
33283329

33293330
static PyObject *
33303331
test_vararg_and_posonly(PyObject *module, PyObject *const *args, Py_ssize_t nargs)
33313332
{
33323333
PyObject *return_value = NULL;
33333334
PyObject *a;
3334-
PyObject *__clinic_args = NULL;
3335+
PyObject *const *__clinic_args = NULL;
33353336

33363337
if (!_PyArg_CheckPositional("test_vararg_and_posonly", nargs, 1, PY_SSIZE_T_MAX)) {
33373338
goto exit;
@@ -3341,16 +3342,16 @@ test_vararg_and_posonly(PyObject *module, PyObject *const *args, Py_ssize_t narg
33413342
for (Py_ssize_t i = 0; i < nargs - 1; ++i) {
33423343
PyTuple_SET_ITEM(__clinic_args, i, args[1 + i]);
33433344
}
3344-
return_value = test_vararg_and_posonly_impl(module, a, __clinic_args);
3345+
return_value = test_vararg_and_posonly_impl(module, a, varargssize, __clinic_args);
33453346

33463347
exit:
3347-
Py_XDECREF(__clinic_args);
33483348
return return_value;
33493349
}
33503350

33513351
static PyObject *
3352-
test_vararg_and_posonly_impl(PyObject *module, PyObject *a, PyObject *args)
3353-
/*[clinic end generated code: output=ada613d2d87c9341 input=08dc2bf7afbf1613]*/
3352+
test_vararg_and_posonly_impl(PyObject *module, PyObject *a,
3353+
Py_ssize_t varargssize, PyObject *const *args)
3354+
/*[clinic end generated code: output=6a6c69c6ff7deb9b input=08dc2bf7afbf1613]*/
33543355

33553356
/*[clinic input]
33563357
test_vararg
@@ -3370,7 +3371,8 @@ PyDoc_STRVAR(test_vararg__doc__,
33703371
{"test_vararg", (PyCFunction)(void(*)(void))test_vararg, METH_FASTCALL|METH_KEYWORDS, test_vararg__doc__},
33713372

33723373
static PyObject *
3373-
test_vararg_impl(PyObject *module, PyObject *a, PyObject *args);
3374+
test_vararg_impl(PyObject *module, PyObject *a, Py_ssize_t varargssize,
3375+
PyObject *const *args);
33743376

33753377
static PyObject *
33763378
test_vararg(PyObject *module, PyObject *const *args, Py_ssize_t nargs, PyObject *kwnames)
@@ -3379,26 +3381,27 @@ test_vararg(PyObject *module, PyObject *const *args, Py_ssize_t nargs, PyObject
33793381
static const char * const _keywords[] = {"a", NULL};
33803382
static _PyArg_Parser _parser = {NULL, _keywords, "test_vararg", 0};
33813383
PyObject *argsbuf[2];
3384+
Py_ssize_t varargssize = Py_MAX(nargs - 1, 0);
33823385
Py_ssize_t noptargs = 0 + (kwnames ? PyTuple_GET_SIZE(kwnames) : 0) - 1;
33833386
PyObject *a;
3384-
PyObject *__clinic_args = NULL;
3387+
PyObject *const *__clinic_args = NULL;
33853388

3386-
args = _PyArg_UnpackKeywordsWithVararg(args, nargs, NULL, kwnames, &_parser, 1, 1, 0, 1, argsbuf);
3389+
args = _PyArg_UnpackKeywordsWithVararg(args, nargs, NULL, kwnames, &_parser, 1, 1, 0, 1, varargssize, argsbuf);
33873390
if (!args) {
33883391
goto exit;
33893392
}
33903393
a = args[0];
3391-
__clinic_args = args[1];
3392-
return_value = test_vararg_impl(module, a, __clinic_args);
3394+
__clinic_args = (PyObject *const *)args[1];
3395+
return_value = test_vararg_impl(module, a, varargssize, __clinic_args);
33933396

33943397
exit:
3395-
Py_XDECREF(__clinic_args);
33963398
return return_value;
33973399
}
33983400

33993401
static PyObject *
3400-
test_vararg_impl(PyObject *module, PyObject *a, PyObject *args)
3401-
/*[clinic end generated code: output=f721025731c3bfe8 input=81d33815ad1bae6e]*/
3402+
test_vararg_impl(PyObject *module, PyObject *a, Py_ssize_t varargssize,
3403+
PyObject *const *args)
3404+
/*[clinic end generated code: output=9f3d65086405e9b6 input=81d33815ad1bae6e]*/
34023405

34033406
/*[clinic input]
34043407
test_vararg_with_default
@@ -3419,7 +3422,8 @@ PyDoc_STRVAR(test_vararg_with_default__doc__,
34193422
{"test_vararg_with_default", (PyCFunction)(void(*)(void))test_vararg_with_default, METH_FASTCALL|METH_KEYWORDS, test_vararg_with_default__doc__},
34203423

34213424
static PyObject *
3422-
test_vararg_with_default_impl(PyObject *module, PyObject *a, PyObject *args,
3425+
test_vararg_with_default_impl(PyObject *module, PyObject *a,
3426+
Py_ssize_t varargssize, PyObject *const *args,
34233427
int b);
34243428

34253429
static PyObject *
@@ -3429,17 +3433,18 @@ test_vararg_with_default(PyObject *module, PyObject *const *args, Py_ssize_t nar
34293433
static const char * const _keywords[] = {"a", "b", NULL};
34303434
static _PyArg_Parser _parser = {NULL, _keywords, "test_vararg_with_default", 0};
34313435
PyObject *argsbuf[3];
3436+
Py_ssize_t varargssize = Py_MAX(nargs - 1, 0);
34323437
Py_ssize_t noptargs = 0 + (kwnames ? PyTuple_GET_SIZE(kwnames) : 0) - 1;
34333438
PyObject *a;
3434-
PyObject *__clinic_args = NULL;
3439+
PyObject *const *__clinic_args = NULL;
34353440
int b = 0;
34363441

3437-
args = _PyArg_UnpackKeywordsWithVararg(args, nargs, NULL, kwnames, &_parser, 1, 1, 0, 1, argsbuf);
3442+
args = _PyArg_UnpackKeywordsWithVararg(args, nargs, NULL, kwnames, &_parser, 1, 1, 0, 1, varargssize, argsbuf);
34383443
if (!args) {
34393444
goto exit;
34403445
}
34413446
a = args[0];
3442-
__clinic_args = args[1];
3447+
__clinic_args = (PyObject *const *)args[1];
34433448
if (!noptargs) {
34443449
goto skip_optional_kwonly;
34453450
}
@@ -3448,17 +3453,17 @@ test_vararg_with_default(PyObject *module, PyObject *const *args, Py_ssize_t nar
34483453
goto exit;
34493454
}
34503455
skip_optional_kwonly:
3451-
return_value = test_vararg_with_default_impl(module, a, __clinic_args, b);
3456+
return_value = test_vararg_with_default_impl(module, a, varargssize, __clinic_args, b);
34523457

34533458
exit:
3454-
Py_XDECREF(__clinic_args);
34553459
return return_value;
34563460
}
34573461

34583462
static PyObject *
3459-
test_vararg_with_default_impl(PyObject *module, PyObject *a, PyObject *args,
3463+
test_vararg_with_default_impl(PyObject *module, PyObject *a,
3464+
Py_ssize_t varargssize, PyObject *const *args,
34603465
int b)
3461-
/*[clinic end generated code: output=63b34d3241c52fda input=6e110b54acd9b22d]*/
3466+
/*[clinic end generated code: output=711a606d86d09fec input=6e110b54acd9b22d]*/
34623467

34633468
/*[clinic input]
34643469
test_vararg_with_only_defaults
@@ -3479,7 +3484,8 @@ PyDoc_STRVAR(test_vararg_with_only_defaults__doc__,
34793484
{"test_vararg_with_only_defaults", (PyCFunction)(void(*)(void))test_vararg_with_only_defaults, METH_FASTCALL|METH_KEYWORDS, test_vararg_with_only_defaults__doc__},
34803485

34813486
static PyObject *
3482-
test_vararg_with_only_defaults_impl(PyObject *module, PyObject *args, int b,
3487+
test_vararg_with_only_defaults_impl(PyObject *module, Py_ssize_t varargssize,
3488+
PyObject *const *args, int b,
34833489
PyObject *c);
34843490

34853491
static PyObject *
@@ -3489,16 +3495,17 @@ test_vararg_with_only_defaults(PyObject *module, PyObject *const *args, Py_ssize
34893495
static const char * const _keywords[] = {"b", "c", NULL};
34903496
static _PyArg_Parser _parser = {NULL, _keywords, "test_vararg_with_only_defaults", 0};
34913497
PyObject *argsbuf[3];
3498+
Py_ssize_t varargssize = Py_MAX(nargs - 0, 0);
34923499
Py_ssize_t noptargs = 0 + (kwnames ? PyTuple_GET_SIZE(kwnames) : 0) - 0;
3493-
PyObject *__clinic_args = NULL;
3500+
PyObject *const *__clinic_args = NULL;
34943501
int b = 0;
34953502
PyObject *c = " ";
34963503

3497-
args = _PyArg_UnpackKeywordsWithVararg(args, nargs, NULL, kwnames, &_parser, 0, 0, 0, 0, argsbuf);
3504+
args = _PyArg_UnpackKeywordsWithVararg(args, nargs, NULL, kwnames, &_parser, 0, 0, 0, 0, varargssize, argsbuf);
34983505
if (!args) {
34993506
goto exit;
35003507
}
3501-
__clinic_args = args[0];
3508+
__clinic_args = (PyObject *const *)args[0];
35023509
if (!noptargs) {
35033510
goto skip_optional_kwonly;
35043511
}
@@ -3513,14 +3520,14 @@ test_vararg_with_only_defaults(PyObject *module, PyObject *const *args, Py_ssize
35133520
}
35143521
c = args[2];
35153522
skip_optional_kwonly:
3516-
return_value = test_vararg_with_only_defaults_impl(module, __clinic_args, b, c);
3523+
return_value = test_vararg_with_only_defaults_impl(module, varargssize, __clinic_args, b, c);
35173524

35183525
exit:
3519-
Py_XDECREF(__clinic_args);
35203526
return return_value;
35213527
}
35223528

35233529
static PyObject *
3524-
test_vararg_with_only_defaults_impl(PyObject *module, PyObject *args, int b,
3530+
test_vararg_with_only_defaults_impl(PyObject *module, Py_ssize_t varargssize,
3531+
PyObject *const *args, int b,
35253532
PyObject *c)
3526-
/*[clinic end generated code: output=dc29ce6ebc2ec10c input=fa56a709a035666e]*/
3533+
/*[clinic end generated code: output=f1415a05ea48fc50 input=fa56a709a035666e]*/

‎Python/getargs.c‎

Lines changed: 6 additions & 20 deletions
Original file line numberDiff line numberDiff line change
@@ -2470,11 +2470,11 @@ _PyArg_UnpackKeywordsWithVararg(PyObject *const *args, Py_ssize_t nargs,
24702470
PyObject *kwargs, PyObject *kwnames,
24712471
struct _PyArg_Parser *parser,
24722472
int minpos, int maxpos, int minkw,
2473-
int vararg, PyObject **buf)
2473+
int vararg, Py_ssize_t varargssize,
2474+
PyObject **buf)
24742475
{
24752476
PyObject *kwtuple;
24762477
PyObject *keyword;
2477-
Py_ssize_t varargssize = 0;
24782478
int i, posonly, minposonly, maxargs;
24792479
int reqlimit = minkw ? maxpos + minkw : minpos;
24802480
Py_ssize_t nkwargs;
@@ -2529,26 +2529,12 @@ _PyArg_UnpackKeywordsWithVararg(PyObject *const *args, Py_ssize_t nargs,
25292529
return NULL;
25302530
}
25312531

2532-
/* create varargs tuple */
2533-
varargssize = nargs - maxpos;
2534-
if (varargssize < 0) {
2535-
varargssize = 0;
2536-
}
2537-
buf[vararg] = PyTuple_New(varargssize);
2538-
if (!buf[vararg]) {
2539-
return NULL;
2540-
}
2532+
/* pass varargs by pointer */
2533+
buf[vararg] = (PyObject *)&args[vararg];
25412534

2542-
/* copy tuple args */
2543-
for (i = 0; i < nargs; i++) {
2544-
if (i >= vararg) {
2545-
Py_INCREF(args[i]);
2546-
PyTuple_SET_ITEM(buf[vararg], i - vararg, args[i]);
2547-
continue;
2548-
}
2549-
else {
2535+
/* copy required positional args */
2536+
for (i = 0; i < vararg; i++) {
25502537
buf[i] = args[i];
2551-
}
25522538
}
25532539

25542540
/* copy keyword args using kwtuple to drive process */

‎Tools/clinic/clinic.py‎

Lines changed: 10 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -942,7 +942,7 @@ def parser_body(prototype, *fields, declarations=''):
942942
min_kw_only
943943
)
944944
else:
945-
args_declaration = "_PyArg_UnpackKeywordsWithVararg", "%s, %s, %s, %s" % (
945+
args_declaration = "_PyArg_UnpackKeywordsWithVararg", "%s, %s, %s, %s, varargssize" % (
946946
min_pos,
947947
max_pos,
948948
min_kw_only,
@@ -957,6 +957,8 @@ def parser_body(prototype, *fields, declarations=''):
957957
static _PyArg_Parser _parser = {{NULL, _keywords, "{name}", 0}};
958958
PyObject *argsbuf[%s];
959959
""" % len(converters))
960+
if vararg != NO_VARARG:
961+
declarations += "\nPy_ssize_t varargssize = Py_MAX(nargs - %d, 0);" % (max_pos)
960962
if has_optional_kw:
961963
pre_buffer = "0" if vararg != NO_VARARG else "nargs"
962964
declarations += "\nPy_ssize_t noptargs = %s + (kwnames ? PyTuple_GET_SIZE(kwnames) : 0) - %d;" % (pre_buffer, min_pos + min_kw_only)
@@ -994,6 +996,8 @@ def parser_body(prototype, *fields, declarations=''):
994996
add_label = None
995997
for i, p in enumerate(parameters):
996998
displayname = p.get_displayname(i+1)
999+
if p.is_vararg():
1000+
p.converter.type = 'PyObject *const *'
9971001
parsearg = p.converter.parse_arg(argname_fmt % i, displayname)
9981002
if parsearg is None:
9991003
#print('Cannot convert %s %r for %s' % (p.converter.__class__.__name__, p.converter.format_unit, p.converter.name), file=sys.stderr)
@@ -1305,9 +1309,6 @@ def render_function(self, clinic, f):
13051309
if (i != -1) and (p.default is not unspecified):
13061310
first_optional = min(first_optional, i)
13071311

1308-
if p.is_vararg():
1309-
data.cleanup.append("Py_XDECREF({});".format(c.parser_name))
1310-
13111312
# insert group variable
13121313
group = p.group
13131314
if last_group != group:
@@ -1319,6 +1320,11 @@ def render_function(self, clinic, f):
13191320
data.impl_parameters.append("int " + group_name)
13201321
has_option_groups = True
13211322

1323+
if p.is_vararg():
1324+
p.converter.type = 'PyObject *const *'
1325+
data.impl_arguments.append('varargssize')
1326+
data.impl_parameters.append('Py_ssize_t varargssize')
1327+
13221328
c.render(p, data)
13231329

13241330
if has_option_groups and (not positional):

0 commit comments

Comments
 (0)