]> git.ipfire.org Git - thirdparty/Python/cpython.git/commitdiff
GH-98831: Add DECREF_INPUTS(), expanding to DECREF() each stack input (#100205)
authorGuido van Rossum <guido@python.org>
Sat, 17 Dec 2022 04:45:55 +0000 (20:45 -0800)
committerGitHub <noreply@github.com>
Sat, 17 Dec 2022 04:45:55 +0000 (20:45 -0800)
The presence of this macro indicates that a particular instruction
may be considered for conversion to a register-based format
(see https://github.com/faster-cpython/ideas/issues/485).

An invariant (currently unchecked) is that `DEOPT_IF()` may only
occur *before* `DECREF_INPUTS()`, and `ERROR_IF()` may only occur
*after* it. One reason not to check this is that there are a few
places where we insert *two* `DECREF_INPUTS()` calls, in different
branches of the code. The invariant checking would have to be able
to do some flow control analysis to understand this.

Note that many instructions, especially specialized ones,
can't be converted to use this macro straightforwardly.
This is because the generator currently only generates plain
`Py_DECREF(variable)` statements, and cannot generate
things like `_Py_DECREF_SPECIALIZED()` let alone deal with
`_PyList_AppendTakeRef()`.

Python/bytecodes.c
Tools/cases_generator/generate_cases.py

index 8e95b737030252d784c86cc0ee9fcf1ce1e895da..b29e16e080e961c4df49ce69c079ee3700af1bab 100644 (file)
@@ -161,7 +161,7 @@ dummy_func(
         super(LOAD_CONST__LOAD_FAST) = LOAD_CONST + LOAD_FAST;
 
         inst(POP_TOP, (value --)) {
-            Py_DECREF(value);
+            DECREF_INPUTS();
         }
 
         inst(PUSH_NULL, (-- res)) {
@@ -172,19 +172,19 @@ dummy_func(
 
         inst(UNARY_POSITIVE, (value -- res)) {
             res = PyNumber_Positive(value);
-            Py_DECREF(value);
+            DECREF_INPUTS();
             ERROR_IF(res == NULL, error);
         }
 
         inst(UNARY_NEGATIVE, (value -- res)) {
             res = PyNumber_Negative(value);
-            Py_DECREF(value);
+            DECREF_INPUTS();
             ERROR_IF(res == NULL, error);
         }
 
         inst(UNARY_NOT, (value -- res)) {
             int err = PyObject_IsTrue(value);
-            Py_DECREF(value);
+            DECREF_INPUTS();
             ERROR_IF(err < 0, error);
             if (err == 0) {
                 res = Py_True;
@@ -197,7 +197,7 @@ dummy_func(
 
         inst(UNARY_INVERT, (value -- res)) {
             res = PyNumber_Invert(value);
-            Py_DECREF(value);
+            DECREF_INPUTS();
             ERROR_IF(res == NULL, error);
         }
 
@@ -351,8 +351,7 @@ dummy_func(
             STAT_INC(BINARY_SUBSCR, deferred);
             DECREMENT_ADAPTIVE_COUNTER(cache->counter);
             res = PyObject_GetItem(container, sub);
-            Py_DECREF(container);
-            Py_DECREF(sub);
+            DECREF_INPUTS();
             ERROR_IF(res == NULL, error);
         }
 
@@ -438,8 +437,7 @@ dummy_func(
                 ERROR_IF(true, error);
             }
             Py_INCREF(res);  // Do this before DECREF'ing dict, sub
-            Py_DECREF(dict);
-            Py_DECREF(sub);
+            DECREF_INPUTS();
         }
 
         inst(BINARY_SUBSCR_GETITEM, (unused/1, type_version/2, func_version/1, container, sub -- unused)) {
@@ -500,9 +498,7 @@ dummy_func(
             DECREMENT_ADAPTIVE_COUNTER(cache->counter);
             /* container[sub] = v */
             int err = PyObject_SetItem(container, sub, v);
-            Py_DECREF(v);
-            Py_DECREF(container);
-            Py_DECREF(sub);
+            DECREF_INPUTS();
             ERROR_IF(err, error);
         }
 
@@ -538,8 +534,7 @@ dummy_func(
         inst(DELETE_SUBSCR, (container, sub --)) {
             /* del container[sub] */
             int err = PyObject_DelItem(container, sub);
-            Py_DECREF(container);
-            Py_DECREF(sub);
+            DECREF_INPUTS();
             ERROR_IF(err, error);
         }
 
@@ -550,11 +545,11 @@ dummy_func(
             if (hook == NULL) {
                 _PyErr_SetString(tstate, PyExc_RuntimeError,
                                  "lost sys.displayhook");
-                Py_DECREF(value);
+                DECREF_INPUTS();
                 ERROR_IF(true, error);
             }
             res = PyObject_CallOneArg(hook, value);
-            Py_DECREF(value);
+            DECREF_INPUTS();
             ERROR_IF(res == NULL, error);
             Py_DECREF(res);
         }
@@ -625,12 +620,12 @@ dummy_func(
                               "'async for' requires an object with "
                               "__aiter__ method, got %.100s",
                               type->tp_name);
-                Py_DECREF(obj);
+                DECREF_INPUTS();
                 ERROR_IF(true, error);
             }
 
             iter = (*getter)(obj);
-            Py_DECREF(obj);
+            DECREF_INPUTS();
             ERROR_IF(iter == NULL, error);
 
             if (Py_TYPE(iter)->tp_as_async == NULL ||
index 2dfc76f2560eae083512f4191a2af3471914c9de..85a7c6098e0b954f65b66e58e24685ac1d825141 100644 (file)
@@ -209,7 +209,7 @@ class Instruction:
             cache_offset += ceffect.size
         assert cache_offset == self.cache_offset + cache_adjust
 
-        # Write the body, substituting a goto for ERROR_IF()
+        # Write the body, substituting a goto for ERROR_IF() and other stuff
         assert dedent <= 0
         extra = " " * -dedent
         for line in self.block_text:
@@ -232,6 +232,10 @@ class Instruction:
                     )
                 else:
                     out.write_raw(f"{extra}{space}if ({cond}) goto {label};\n")
+            elif m := re.match(r"(\s*)DECREF_INPUTS\(\);\s*$", line):
+                space = m.group(1)
+                for ieff in self.input_effects:
+                    out.write_raw(f"{extra}{space}Py_DECREF({ieff.name});\n")
             else:
                 out.write_raw(extra + line)