The newly allocated argument vector supports PY_VECTORCALL_ARGUMENTS_OFFSET.
+ The positional arguments are borrowed references from the input array
+ (which must be kept alive by the caller). The keyword argument values
+ are new references.
+
When done, you must call _PyStack_UnpackDict_Free(stack, nargs, kwnames) */
PyObject *const *
_PyStack_UnpackDict(PyThreadState *tstate,
stack++; /* For PY_VECTORCALL_ARGUMENTS_OFFSET */
- /* Copy positional arguments */
+ /* Copy positional arguments (borrowed references) */
for (Py_ssize_t i = 0; i < nargs; i++) {
- stack[i] = Py_NewRef(args[i]);
+ stack[i] = args[i];
}
PyObject **kwstack = stack + nargs;
_PyStack_UnpackDict_Free(PyObject *const *stack, Py_ssize_t nargs,
PyObject *kwnames)
{
- Py_ssize_t n = PyTuple_GET_SIZE(kwnames) + nargs;
- for (Py_ssize_t i = 0; i < n; i++) {
- Py_DECREF(stack[i]);
+ /* Only decref kwargs values, positional args are borrowed */
+ Py_ssize_t nkwargs = PyTuple_GET_SIZE(kwnames);
+ for (Py_ssize_t i = 0; i < nkwargs; i++) {
+ Py_DECREF(stack[nargs + i]);
}
_PyStack_UnpackDict_FreeNoDecRef(stack, kwnames);
}
PyStackRef_CLOSE(func);
goto error;
}
- size_t total_args = nargs + PyDict_GET_SIZE(kwargs);
+ size_t nkwargs = PyDict_GET_SIZE(kwargs);
assert(sizeof(PyObject *) == sizeof(_PyStackRef));
newargs = (_PyStackRef *)object_array;
- for (size_t i = 0; i < total_args; i++) {
- newargs[i] = PyStackRef_FromPyObjectSteal(object_array[i]);
+ /* Positional args are borrowed from callargs tuple, need new reference */
+ for (Py_ssize_t i = 0; i < nargs; i++) {
+ newargs[i] = PyStackRef_FromPyObjectNew(object_array[i]);
+ }
+ /* Keyword args are owned by _PyStack_UnpackDict, steal them */
+ for (size_t i = 0; i < nkwargs; i++) {
+ newargs[nargs + i] = PyStackRef_FromPyObjectSteal(object_array[nargs + i]);
}
}
else {