Skip to content

Commit 91fb626

Browse files
colesburyestyxx
authored andcommitted
pythongh-117139: Add _PyTuple_FromStackRefSteal and use it (python#121244)
Avoids the extra conversion from stack refs to PyObjects.
1 parent fb74b85 commit 91fb626

File tree

8 files changed

+28
-33
lines changed

8 files changed

+28
-33
lines changed

Include/internal/pycore_stackref.h

+1-1
Original file line numberDiff line numberDiff line change
@@ -48,7 +48,7 @@ extern "C" {
4848
CPython refcounting operations on it!
4949
*/
5050

51-
typedef union {
51+
typedef union _PyStackRef {
5252
uintptr_t bits;
5353
} _PyStackRef;
5454

Include/internal/pycore_tuple.h

+1
Original file line numberDiff line numberDiff line change
@@ -21,6 +21,7 @@ extern PyStatus _PyTuple_InitGlobalObjects(PyInterpreterState *);
2121
#define _PyTuple_ITEMS(op) _Py_RVALUE(_PyTuple_CAST(op)->ob_item)
2222

2323
extern PyObject *_PyTuple_FromArray(PyObject *const *, Py_ssize_t);
24+
PyAPI_FUNC(PyObject *)_PyTuple_FromStackRefSteal(const union _PyStackRef *, Py_ssize_t);
2425
PyAPI_FUNC(PyObject *)_PyTuple_FromArraySteal(PyObject *const *, Py_ssize_t);
2526

2627
typedef struct {

Objects/tupleobject.c

+21
Original file line numberDiff line numberDiff line change
@@ -390,6 +390,27 @@ _PyTuple_FromArray(PyObject *const *src, Py_ssize_t n)
390390
return (PyObject *)tuple;
391391
}
392392

393+
PyObject *
394+
_PyTuple_FromStackRefSteal(const _PyStackRef *src, Py_ssize_t n)
395+
{
396+
if (n == 0) {
397+
return tuple_get_empty();
398+
}
399+
PyTupleObject *tuple = tuple_alloc(n);
400+
if (tuple == NULL) {
401+
for (Py_ssize_t i = 0; i < n; i++) {
402+
PyStackRef_CLOSE(src[i]);
403+
}
404+
return NULL;
405+
}
406+
PyObject **dst = tuple->ob_item;
407+
for (Py_ssize_t i = 0; i < n; i++) {
408+
dst[i] = PyStackRef_AsPyObjectSteal(src[i]);
409+
}
410+
_PyObject_GC_TRACK(tuple);
411+
return (PyObject *)tuple;
412+
}
413+
393414
PyObject *
394415
_PyTuple_FromArraySteal(PyObject *const *src, Py_ssize_t n)
395416
{

Python/bytecodes.c

+1-7
Original file line numberDiff line numberDiff line change
@@ -1780,13 +1780,7 @@ dummy_func(
17801780
}
17811781

17821782
inst(BUILD_TUPLE, (values[oparg] -- tup)) {
1783-
STACKREFS_TO_PYOBJECTS(values, oparg, values_o);
1784-
if (CONVERSION_FAILED(values_o)) {
1785-
DECREF_INPUTS();
1786-
ERROR_IF(true, error);
1787-
}
1788-
PyObject *tup_o = _PyTuple_FromArraySteal(values_o, oparg);
1789-
STACKREFS_TO_PYOBJECTS_CLEANUP(values_o);
1783+
PyObject *tup_o = _PyTuple_FromStackRefSteal(values, oparg);
17901784
ERROR_IF(tup_o == NULL, error);
17911785
tup = PyStackRef_FromPyObjectSteal(tup_o);
17921786
}

Python/ceval.c

+1-7
Original file line numberDiff line numberDiff line change
@@ -1500,13 +1500,7 @@ initialize_locals(PyThreadState *tstate, PyFunctionObject *func,
15001500
u = (PyObject *)&_Py_SINGLETON(tuple_empty);
15011501
}
15021502
else {
1503-
assert(args != NULL);
1504-
STACKREFS_TO_PYOBJECTS((_PyStackRef *)args, argcount, args_o);
1505-
if (args_o == NULL) {
1506-
goto fail_pre_positional;
1507-
}
1508-
u = _PyTuple_FromArraySteal((args_o + n), argcount - n);
1509-
STACKREFS_TO_PYOBJECTS_CLEANUP(args_o);
1503+
u = _PyTuple_FromStackRefSteal(args + n, argcount - n);
15101504
}
15111505
if (u == NULL) {
15121506
goto fail_post_positional;

Python/executor_cases.c.h

+1-9
Some generated files are not rendered by default. Learn more about customizing how changed files appear on GitHub.

Python/generated_cases.c.h

+1-9
Some generated files are not rendered by default. Learn more about customizing how changed files appear on GitHub.

Tools/cases_generator/analyzer.py

+1
Original file line numberDiff line numberDiff line change
@@ -431,6 +431,7 @@ def has_error_without_pop(op: parser.InstDef) -> bool:
431431
"CONVERSION_FAILED",
432432
"_PyList_FromArraySteal",
433433
"_PyTuple_FromArraySteal",
434+
"_PyTuple_FromStackRefSteal",
434435
)
435436

436437
ESCAPING_FUNCTIONS = (

0 commit comments

Comments
 (0)