Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

gh-90370: avoid temporary tuple creation for vararg in AC #126064

Merged
merged 9 commits into from
Oct 31, 2024
48 changes: 21 additions & 27 deletions Lib/test/clinic.test.c
Original file line number Diff line number Diff line change
Expand Up @@ -4148,36 +4148,32 @@ PyDoc_STRVAR(test_vararg_and_posonly__doc__,
{"test_vararg_and_posonly", _PyCFunction_CAST(test_vararg_and_posonly), METH_FASTCALL, test_vararg_and_posonly__doc__},

static PyObject *
test_vararg_and_posonly_impl(PyObject *module, PyObject *a, PyObject *args);
test_vararg_and_posonly_impl(PyObject *module, PyObject *a, Py_ssize_t nargs,
PyObject *const *args);

static PyObject *
test_vararg_and_posonly(PyObject *module, PyObject *const *args, Py_ssize_t nargs)
{
PyObject *return_value = NULL;
Py_ssize_t nvararg = nargs - 1;
PyObject *a;
PyObject *__clinic_args = NULL;
PyObject *const *__clinic_args = NULL;

if (!_PyArg_CheckPositional("test_vararg_and_posonly", nargs, 1, PY_SSIZE_T_MAX)) {
goto exit;
}
a = args[0];
__clinic_args = PyTuple_New(nargs - 1);
if (!__clinic_args) {
goto exit;
}
for (Py_ssize_t i = 0; i < nargs - 1; ++i) {
PyTuple_SET_ITEM(__clinic_args, i, Py_NewRef(args[1 + i]));
}
return_value = test_vararg_and_posonly_impl(module, a, __clinic_args);
__clinic_args = args + 1;
return_value = test_vararg_and_posonly_impl(module, a, nvararg, __clinic_args);

exit:
Py_XDECREF(__clinic_args);
return return_value;
}

static PyObject *
test_vararg_and_posonly_impl(PyObject *module, PyObject *a, PyObject *args)
/*[clinic end generated code: output=79b75dc07decc8d6 input=9cfa748bbff09877]*/
test_vararg_and_posonly_impl(PyObject *module, PyObject *a, Py_ssize_t nargs,
PyObject *const *args)
/*[clinic end generated code: output=dc2dd9483cc0459e input=9cfa748bbff09877]*/

/*[clinic input]
test_vararg
Expand Down Expand Up @@ -4931,14 +4927,14 @@ PyDoc_STRVAR(Test___init____doc__,
"Varargs init method. For example, nargs is translated to PyTuple_GET_SIZE.");

static int
Test___init___impl(TestObj *self, PyObject *args);
Test___init___impl(TestObj *self, Py_ssize_t nargs, PyObject *const *args);

static int
Test___init__(PyObject *self, PyObject *args, PyObject *kwargs)
{
int return_value = -1;
PyTypeObject *base_tp = TestType;
PyObject *__clinic_args = NULL;
PyObject *const *__clinic_args = NULL;

if ((Py_IS_TYPE(self, base_tp) ||
Py_TYPE(self)->tp_new == base_tp->tp_new) &&
Expand All @@ -4948,17 +4944,16 @@ Test___init__(PyObject *self, PyObject *args, PyObject *kwargs)
if (!_PyArg_CheckPositional("Test", PyTuple_GET_SIZE(args), 0, PY_SSIZE_T_MAX)) {
goto exit;
}
__clinic_args = PyTuple_GetSlice(0, -1);
return_value = Test___init___impl((TestObj *)self, __clinic_args);
__clinic_args = _PyTuple_CAST(args)->ob_item;
return_value = Test___init___impl((TestObj *)self, nvararg, __clinic_args);

exit:
Py_XDECREF(__clinic_args);
return return_value;
}

static int
Test___init___impl(TestObj *self, PyObject *args)
/*[clinic end generated code: output=0ed1009fe0dcf98d input=2a8bd0033c9ac772]*/
Test___init___impl(TestObj *self, Py_ssize_t nargs, PyObject *const *args)
/*[clinic end generated code: output=6a64b417c9080a73 input=2a8bd0033c9ac772]*/


/*[clinic input]
Expand All @@ -4976,14 +4971,14 @@ PyDoc_STRVAR(Test__doc__,
"Varargs new method. For example, nargs is translated to PyTuple_GET_SIZE.");

static PyObject *
Test_impl(PyTypeObject *type, PyObject *args);
Test_impl(PyTypeObject *type, Py_ssize_t nargs, PyObject *const *args);

static PyObject *
Test(PyTypeObject *type, PyObject *args, PyObject *kwargs)
{
PyObject *return_value = NULL;
PyTypeObject *base_tp = TestType;
PyObject *__clinic_args = NULL;
PyObject *const *__clinic_args = NULL;

if ((type == base_tp || type->tp_init == base_tp->tp_init) &&
!_PyArg_NoKeywords("Test", kwargs)) {
Expand All @@ -4992,17 +4987,16 @@ Test(PyTypeObject *type, PyObject *args, PyObject *kwargs)
if (!_PyArg_CheckPositional("Test", PyTuple_GET_SIZE(args), 0, PY_SSIZE_T_MAX)) {
goto exit;
}
__clinic_args = PyTuple_GetSlice(0, -1);
return_value = Test_impl(type, __clinic_args);
__clinic_args = _PyTuple_CAST(args)->ob_item;
return_value = Test_impl(type, nvararg, __clinic_args);

exit:
Py_XDECREF(__clinic_args);
return return_value;
}

static PyObject *
Test_impl(PyTypeObject *type, PyObject *args)
/*[clinic end generated code: output=8b219f6633e2a2e9 input=70ad829df3dd9b84]*/
Test_impl(PyTypeObject *type, Py_ssize_t nargs, PyObject *const *args)
/*[clinic end generated code: output=bf22f942407383a5 input=70ad829df3dd9b84]*/


/*[clinic input]
Expand Down
4 changes: 2 additions & 2 deletions Lib/test/test_clinic.py
Original file line number Diff line number Diff line change
Expand Up @@ -3381,8 +3381,8 @@ def test_keyword_only_parameter(self):
def test_varpos(self):
# fn(*args)
fn = ac_tester.varpos
self.assertEqual(fn(), ())
self.assertEqual(fn(1, 2), (1, 2))
self.assertEqual(fn(), ((),))
self.assertEqual(fn(1, 2), ((1, 2),))

def test_posonly_varpos(self):
# fn(a, b, /, *args)
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,2 @@
Avoid temporary tuple creation for vararg in argument passing with Argument
Clinic generated code (if arguments either vararg or positional-only).
43 changes: 35 additions & 8 deletions Modules/_testclinic.c
Original file line number Diff line number Diff line change
Expand Up @@ -58,6 +58,20 @@ pack_arguments_newref(int argc, ...)
return tuple;
}

static PyObject *
pack_varargs_to_tuple(Py_ssize_t varargssize, PyObject *const *args)
{
assert(!PyErr_Occurred());
PyObject *tuple = PyTuple_New(varargssize);
if (!tuple) {
return NULL;
}
for (Py_ssize_t i = 0; i < varargssize; i++) {
PyTuple_SET_ITEM(tuple, i, Py_NewRef(args[i]));
}
return tuple;
}

/* Pack arguments to a tuple.
* `wrapper` is function which converts primitive type to PyObject.
* `arg_type` is type that arguments should be converted to before wrapped. */
Expand Down Expand Up @@ -970,10 +984,16 @@ varpos
[clinic start generated code]*/

static PyObject *
varpos_impl(PyObject *module, PyObject *args)
/*[clinic end generated code: output=7b0b9545872bdca4 input=f87cd674145d394c]*/
varpos_impl(PyObject *module, Py_ssize_t nargs, PyObject *const *args)
/*[clinic end generated code: output=b65096f423fb5dcc input=f87cd674145d394c]*/
{
return Py_NewRef(args);
PyObject *vararg_tuple = pack_varargs_to_tuple(nargs, args);
if (!vararg_tuple) {
return NULL;
}
PyObject *result = pack_arguments_newref(1, vararg_tuple);
Py_DECREF(vararg_tuple);
return result;
}


Expand All @@ -989,10 +1009,16 @@ posonly_varpos

static PyObject *
posonly_varpos_impl(PyObject *module, PyObject *a, PyObject *b,
PyObject *args)
/*[clinic end generated code: output=5dae5eb2a0d623cd input=c9fd7895cfbaabba]*/
Py_ssize_t nargs, PyObject *const *args)
/*[clinic end generated code: output=d10d43d86d117ab3 input=c9fd7895cfbaabba]*/
{
return pack_arguments_newref(3, a, b, args);
PyObject *vararg_tuple = pack_varargs_to_tuple(nargs, args);
if (!vararg_tuple) {
return NULL;
}
PyObject *result = pack_arguments_newref(3, a, b, vararg_tuple);
Py_DECREF(vararg_tuple);
return result;
}


Expand Down Expand Up @@ -1157,8 +1183,9 @@ Proof-of-concept of GH-99233 refcount error bug.
[clinic start generated code]*/

static PyObject *
gh_99233_refcount_impl(PyObject *module, PyObject *args)
/*[clinic end generated code: output=585855abfbca9a7f input=eecfdc2092d90dc3]*/
gh_99233_refcount_impl(PyObject *module, Py_ssize_t nargs,
PyObject *const *args)
/*[clinic end generated code: output=b570007e61e5c670 input=eecfdc2092d90dc3]*/
{
Py_RETURN_NONE;
}
Expand Down
51 changes: 17 additions & 34 deletions Modules/clinic/_testclinic.c.h

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

36 changes: 13 additions & 23 deletions Modules/clinic/gcmodule.c.h

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

Loading
Loading