]> git.ipfire.org Git - thirdparty/Python/cpython.git/commitdiff
gh-117139: Add _PyTuple_FromStackRefSteal and use it (#121244)
authorSam Gross <colesbury@gmail.com>
Tue, 2 Jul 2024 16:30:14 +0000 (12:30 -0400)
committerGitHub <noreply@github.com>
Tue, 2 Jul 2024 16:30:14 +0000 (12:30 -0400)
Avoids the extra conversion from stack refs to PyObjects.

Include/internal/pycore_stackref.h
Include/internal/pycore_tuple.h
Objects/tupleobject.c
Python/bytecodes.c
Python/ceval.c
Python/executor_cases.c.h
Python/generated_cases.c.h
Tools/cases_generator/analyzer.py

index 32e445dd96f9a16d48483bbfc422bd2f99671a0e..4301c6a7cb40b0aa866d0d307553abb0fe3df11e 100644 (file)
@@ -48,7 +48,7 @@ extern "C" {
    CPython refcounting operations on it!
 */
 
-typedef union {
+typedef union _PyStackRef {
     uintptr_t bits;
 } _PyStackRef;
 
index 14a9e42c3a324cd73bd0527fe5ba805f7a91d7b0..dfbbd6fd0c7de563c0a961ca5705568b376eda88 100644 (file)
@@ -21,6 +21,7 @@ extern PyStatus _PyTuple_InitGlobalObjects(PyInterpreterState *);
 #define _PyTuple_ITEMS(op) _Py_RVALUE(_PyTuple_CAST(op)->ob_item)
 
 extern PyObject *_PyTuple_FromArray(PyObject *const *, Py_ssize_t);
+PyAPI_FUNC(PyObject *)_PyTuple_FromStackRefSteal(const union _PyStackRef *, Py_ssize_t);
 PyAPI_FUNC(PyObject *)_PyTuple_FromArraySteal(PyObject *const *, Py_ssize_t);
 
 typedef struct {
index 5ae1ee9a89af84c3fb0478a936fde03a14b957c8..994258f20b495dffa6921e64c3a2b01cd5ec9387 100644 (file)
@@ -390,6 +390,27 @@ _PyTuple_FromArray(PyObject *const *src, Py_ssize_t n)
     return (PyObject *)tuple;
 }
 
+PyObject *
+_PyTuple_FromStackRefSteal(const _PyStackRef *src, Py_ssize_t n)
+{
+    if (n == 0) {
+        return tuple_get_empty();
+    }
+    PyTupleObject *tuple = tuple_alloc(n);
+    if (tuple == NULL) {
+        for (Py_ssize_t i = 0; i < n; i++) {
+            PyStackRef_CLOSE(src[i]);
+        }
+        return NULL;
+    }
+    PyObject **dst = tuple->ob_item;
+    for (Py_ssize_t i = 0; i < n; i++) {
+        dst[i] = PyStackRef_AsPyObjectSteal(src[i]);
+    }
+    _PyObject_GC_TRACK(tuple);
+    return (PyObject *)tuple;
+}
+
 PyObject *
 _PyTuple_FromArraySteal(PyObject *const *src, Py_ssize_t n)
 {
index 343481e9313de489f3e19b15423e10f1741cd745..76587a4f0dc6951b401bcde4c2098e2cb54c3109 100644 (file)
@@ -1780,13 +1780,7 @@ dummy_func(
         }
 
         inst(BUILD_TUPLE, (values[oparg] -- tup)) {
-            STACKREFS_TO_PYOBJECTS(values, oparg, values_o);
-            if (CONVERSION_FAILED(values_o)) {
-                DECREF_INPUTS();
-                ERROR_IF(true, error);
-            }
-            PyObject *tup_o = _PyTuple_FromArraySteal(values_o, oparg);
-            STACKREFS_TO_PYOBJECTS_CLEANUP(values_o);
+            PyObject *tup_o = _PyTuple_FromStackRefSteal(values, oparg);
             ERROR_IF(tup_o == NULL, error);
             tup = PyStackRef_FromPyObjectSteal(tup_o);
         }
index a71244676f3029a87939f8981c4d5f78f0961f82..a240ed4321f7ee0289cf4a2f7c546f06c6d3234e 100644 (file)
@@ -1500,13 +1500,7 @@ initialize_locals(PyThreadState *tstate, PyFunctionObject *func,
             u = (PyObject *)&_Py_SINGLETON(tuple_empty);
         }
         else {
-            assert(args != NULL);
-            STACKREFS_TO_PYOBJECTS((_PyStackRef *)args, argcount, args_o);
-            if (args_o == NULL) {
-                goto fail_pre_positional;
-            }
-            u = _PyTuple_FromArraySteal((args_o + n), argcount - n);
-            STACKREFS_TO_PYOBJECTS_CLEANUP(args_o);
+            u = _PyTuple_FromStackRefSteal(args + n, argcount - n);
         }
         if (u == NULL) {
             goto fail_post_positional;
index d70a57a9a8ffbebaf373d50c537e8250e49f954b..3b999465aac815d905e6bc70a67c9ba6ce287cd4 100644 (file)
             _PyStackRef tup;
             oparg = CURRENT_OPARG();
             values = &stack_pointer[-oparg];
-            STACKREFS_TO_PYOBJECTS(values, oparg, values_o);
-            if (CONVERSION_FAILED(values_o)) {
-                for (int _i = oparg; --_i >= 0;) {
-                    PyStackRef_CLOSE(values[_i]);
-                }
-                if (true) JUMP_TO_ERROR();
-            }
-            PyObject *tup_o = _PyTuple_FromArraySteal(values_o, oparg);
-            STACKREFS_TO_PYOBJECTS_CLEANUP(values_o);
+            PyObject *tup_o = _PyTuple_FromStackRefSteal(values, oparg);
             if (tup_o == NULL) JUMP_TO_ERROR();
             tup = PyStackRef_FromPyObjectSteal(tup_o);
             stack_pointer[-oparg] = tup;
index 32b22aff14a7681c740c25f099d3b32399620be1..61057221291c0a4cf113bbfb6bac6ffa4675021a 100644 (file)
             _PyStackRef *values;
             _PyStackRef tup;
             values = &stack_pointer[-oparg];
-            STACKREFS_TO_PYOBJECTS(values, oparg, values_o);
-            if (CONVERSION_FAILED(values_o)) {
-                for (int _i = oparg; --_i >= 0;) {
-                    PyStackRef_CLOSE(values[_i]);
-                }
-                if (true) { stack_pointer += -oparg; goto error; }
-            }
-            PyObject *tup_o = _PyTuple_FromArraySteal(values_o, oparg);
-            STACKREFS_TO_PYOBJECTS_CLEANUP(values_o);
+            PyObject *tup_o = _PyTuple_FromStackRefSteal(values, oparg);
             if (tup_o == NULL) { stack_pointer += -oparg; goto error; }
             tup = PyStackRef_FromPyObjectSteal(tup_o);
             stack_pointer[-oparg] = tup;
index 6b1af1b59f14d823c1c774b83128591abe7456de..f92560bd2b76b30d45bdd9895c9df5c4f02d081e 100644 (file)
@@ -431,6 +431,7 @@ NON_ESCAPING_FUNCTIONS = (
     "CONVERSION_FAILED",
     "_PyList_FromArraySteal",
     "_PyTuple_FromArraySteal",
+    "_PyTuple_FromStackRefSteal",
 )
 
 ESCAPING_FUNCTIONS = (