]> git.ipfire.org Git - thirdparty/Python/cpython.git/commitdiff
GH-100719: Remove the `co_nplaincellvars` field from code objects. (GH-100721)
authorMark Shannon <mark@hotpy.org>
Wed, 4 Jan 2023 15:41:39 +0000 (15:41 +0000)
committerGitHub <noreply@github.com>
Wed, 4 Jan 2023 15:41:39 +0000 (15:41 +0000)
Include/cpython/code.h
Misc/NEWS.d/next/Core and Builtins/2023-01-03-16-38-18.gh-issue-100719.2C--ko.rst [new file with mode: 0644]
Objects/codeobject.c
Objects/frameobject.c
Objects/typeobject.c
Python/bytecodes.c
Python/ceval.c
Python/compile.c
Python/generated_cases.c.h
Tools/build/deepfreeze.py

index 1c619322926ef4cfe0261520f0d86cb0b20ad4b6..0cf49f06c87732bd62ba0ce2977fa3c6ddd67c15 100644 (file)
@@ -87,7 +87,6 @@ typedef struct {
     int co_nlocalsplus;           /* number of local + cell + free variables */ \
     int co_framesize;             /* Size of frame in words */                 \
     int co_nlocals;               /* number of local variables */              \
-    int co_nplaincellvars;        /* number of non-arg cell variables */       \
     int co_ncellvars;             /* total number of cell variables */         \
     int co_nfreevars;             /* number of free variables */               \
     uint32_t co_version;          /* version number */                         \
@@ -157,6 +156,11 @@ static inline Py_ssize_t PyCode_GetNumFree(PyCodeObject *op) {
     return op->co_nfreevars;
 }
 
+static inline int PyCode_GetFirstFree(PyCodeObject *op) {
+    assert(PyCode_Check(op));
+    return op->co_nlocalsplus - op->co_nfreevars;
+}
+
 #define _PyCode_CODE(CO) _Py_RVALUE((_Py_CODEUNIT *)(CO)->co_code_adaptive)
 #define _PyCode_NBYTES(CO) (Py_SIZE(CO) * (Py_ssize_t)sizeof(_Py_CODEUNIT))
 
diff --git a/Misc/NEWS.d/next/Core and Builtins/2023-01-03-16-38-18.gh-issue-100719.2C--ko.rst b/Misc/NEWS.d/next/Core and Builtins/2023-01-03-16-38-18.gh-issue-100719.2C--ko.rst
new file mode 100644 (file)
index 0000000..bb5d561
--- /dev/null
@@ -0,0 +1,2 @@
+Removed the co_nplaincellvars field from the code object, as it is
+redundant.
index e174c6fee9cc24d05e0053a3fe474b6ac6b16df6..6facfef4c9b4736e1ae8129a8c5bde7259c49701 100644 (file)
@@ -247,11 +247,10 @@ _Py_set_localsplus_info(int offset, PyObject *name, _PyLocals_Kind kind,
 
 static void
 get_localsplus_counts(PyObject *names, PyObject *kinds,
-                      int *pnlocals, int *pnplaincellvars, int *pncellvars,
+                      int *pnlocals, int *pncellvars,
                       int *pnfreevars)
 {
     int nlocals = 0;
-    int nplaincellvars = 0;
     int ncellvars = 0;
     int nfreevars = 0;
     Py_ssize_t nlocalsplus = PyTuple_GET_SIZE(names);
@@ -265,7 +264,6 @@ get_localsplus_counts(PyObject *names, PyObject *kinds,
         }
         else if (kind & CO_FAST_CELL) {
             ncellvars += 1;
-            nplaincellvars += 1;
         }
         else if (kind & CO_FAST_FREE) {
             nfreevars += 1;
@@ -274,9 +272,6 @@ get_localsplus_counts(PyObject *names, PyObject *kinds,
     if (pnlocals != NULL) {
         *pnlocals = nlocals;
     }
-    if (pnplaincellvars != NULL) {
-        *pnplaincellvars = nplaincellvars;
-    }
     if (pncellvars != NULL) {
         *pncellvars = ncellvars;
     }
@@ -351,7 +346,7 @@ _PyCode_Validate(struct _PyCodeConstructor *con)
      * here to avoid the possibility of overflow (however remote). */
     int nlocals;
     get_localsplus_counts(con->localsplusnames, con->localspluskinds,
-                          &nlocals, NULL, NULL, NULL);
+                          &nlocals, NULL, NULL);
     int nplainlocals = nlocals -
                        con->argcount -
                        con->kwonlyargcount -
@@ -371,9 +366,9 @@ static void
 init_code(PyCodeObject *co, struct _PyCodeConstructor *con)
 {
     int nlocalsplus = (int)PyTuple_GET_SIZE(con->localsplusnames);
-    int nlocals, nplaincellvars, ncellvars, nfreevars;
+    int nlocals, ncellvars, nfreevars;
     get_localsplus_counts(con->localsplusnames, con->localspluskinds,
-                          &nlocals, &nplaincellvars, &ncellvars, &nfreevars);
+                          &nlocals, &ncellvars, &nfreevars);
 
     co->co_filename = Py_NewRef(con->filename);
     co->co_name = Py_NewRef(con->name);
@@ -401,7 +396,6 @@ init_code(PyCodeObject *co, struct _PyCodeConstructor *con)
     co->co_nlocalsplus = nlocalsplus;
     co->co_nlocals = nlocals;
     co->co_framesize = nlocalsplus + con->stacksize + FRAME_SPECIALS_SIZE;
-    co->co_nplaincellvars = nplaincellvars;
     co->co_ncellvars = ncellvars;
     co->co_nfreevars = nfreevars;
     co->co_version = _Py_next_func_version;
index 98f0b3838723da994a5ed53ef854210505f24755..8d7ee4b81eb7dcab504a994031da6125acb1fd9b 100644 (file)
@@ -1119,7 +1119,7 @@ frame_init_get_vars(_PyInterpreterFrame *frame)
 
     /* Free vars have not been initialized -- Do that */
     PyObject *closure = ((PyFunctionObject *)frame->f_funcobj)->func_closure;
-    int offset = co->co_nlocals + co->co_nplaincellvars;
+    int offset = PyCode_GetFirstFree(co);
     for (int i = 0; i < co->co_nfreevars; ++i) {
         PyObject *o = PyTuple_GET_ITEM(closure, i);
         frame->localsplus[offset + i] = Py_NewRef(o);
index 43633f044751cabd33d074ce1b2bcd8b03fe9de3..f2d78cf50913ecb933f47eb3684d6ed1d27c9fa8 100644 (file)
@@ -9514,7 +9514,7 @@ super_init_without_args(_PyInterpreterFrame *cframe, PyCodeObject *co,
 
     // Look for __class__ in the free vars.
     PyTypeObject *type = NULL;
-    int i = co->co_nlocals + co->co_nplaincellvars;
+    int i = PyCode_GetFirstFree(co);
     for (; i < co->co_nlocalsplus; i++) {
         assert((_PyLocals_GetKind(co->co_localspluskinds, i) & CO_FAST_FREE) != 0);
         PyObject *name = PyTuple_GET_ITEM(co->co_localsplusnames, i);
index 839fac3fcd1176738c8601f844c90ec9f48f1679..dec122a78223fec5b020ef3352e61c3cec09717d 100644 (file)
@@ -1357,8 +1357,8 @@ dummy_func(
             PyCodeObject *co = frame->f_code;
             assert(PyFunction_Check(frame->f_funcobj));
             PyObject *closure = ((PyFunctionObject *)frame->f_funcobj)->func_closure;
-            int offset = co->co_nlocals + co->co_nplaincellvars;
             assert(oparg == co->co_nfreevars);
+            int offset = co->co_nlocalsplus - oparg;
             for (int i = 0; i < oparg; ++i) {
                 PyObject *o = PyTuple_GET_ITEM(closure, i);
                 frame->localsplus[offset + i] = Py_NewRef(o);
index 45f42800d7ce5861e593b31f98804ef8a7dec4cf..54df1c512502eb6670f75338a27d732d1c874f10 100644 (file)
@@ -3417,7 +3417,7 @@ format_exc_unbound(PyThreadState *tstate, PyCodeObject *co, int oparg)
     if (_PyErr_Occurred(tstate))
         return;
     name = PyTuple_GET_ITEM(co->co_localsplusnames, oparg);
-    if (oparg < co->co_nplaincellvars + co->co_nlocals) {
+    if (oparg < PyCode_GetFirstFree(co)) {
         format_exc_check_arg(tstate, PyExc_UnboundLocalError,
                              UNBOUNDLOCAL_ERROR_MSG, name);
     } else {
index cbbdfb9e946772c60490ae818f6d8fa5af9bd9f2..c2e77fefb084e82bc81d8b6722015fbdd268adfe 100644 (file)
@@ -2260,7 +2260,7 @@ compiler_make_closure(struct compiler *c, location loc,
         qualname = co->co_name;
 
     if (co->co_nfreevars) {
-        int i = co->co_nlocals + co->co_nplaincellvars;
+        int i = PyCode_GetFirstFree(co);
         for (; i < co->co_nlocalsplus; ++i) {
             /* Bypass com_addop_varname because it will generate
                LOAD_DEREF but LOAD_CLOSURE is needed.
index ed89e90b7c564d19f8fa3e60f0688e861e2d7bf5..3218bd091433f9395b6206d28b5a81b87d7e6e73 100644 (file)
             PyCodeObject *co = frame->f_code;
             assert(PyFunction_Check(frame->f_funcobj));
             PyObject *closure = ((PyFunctionObject *)frame->f_funcobj)->func_closure;
-            int offset = co->co_nlocals + co->co_nplaincellvars;
             assert(oparg == co->co_nfreevars);
+            int offset = co->co_nlocalsplus - oparg;
             for (int i = 0; i < oparg; ++i) {
                 PyObject *o = PyTuple_GET_ITEM(closure, i);
                 frame->localsplus[offset + i] = Py_NewRef(o);
index e4b422820f7db787d5fbcfbf0a7bdd6926c8c8eb..511b26a5ce3dc73a7f2046144ee107e7c211ab92 100644 (file)
@@ -61,7 +61,6 @@ def get_localsplus_counts(code: types.CodeType,
                           names: Tuple[str, ...],
                           kinds: bytes) -> Tuple[int, int, int, int]:
     nlocals = 0
-    nplaincellvars = 0
     ncellvars = 0
     nfreevars = 0
     assert len(names) == len(kinds)
@@ -72,15 +71,13 @@ def get_localsplus_counts(code: types.CodeType,
                 ncellvars += 1
         elif kind & CO_FAST_CELL:
             ncellvars += 1
-            nplaincellvars += 1
         elif kind & CO_FAST_FREE:
             nfreevars += 1
     assert nlocals == len(code.co_varnames) == code.co_nlocals, \
         (nlocals, len(code.co_varnames), code.co_nlocals)
     assert ncellvars == len(code.co_cellvars)
     assert nfreevars == len(code.co_freevars)
-    assert len(names) == nlocals + nplaincellvars + nfreevars
-    return nlocals, nplaincellvars, ncellvars, nfreevars
+    return nlocals, ncellvars, nfreevars
 
 
 PyUnicode_1BYTE_KIND = 1
@@ -243,7 +240,7 @@ class Printer:
         co_localsplusnames = self.generate(name + "_localsplusnames", localsplusnames)
         co_localspluskinds = self.generate(name + "_localspluskinds", localspluskinds)
         # Derived values
-        nlocals, nplaincellvars, ncellvars, nfreevars = \
+        nlocals, ncellvars, nfreevars = \
             get_localsplus_counts(code, localsplusnames, localspluskinds)
         co_code_adaptive = make_string_literal(code.co_code)
         self.write("static")
@@ -268,7 +265,6 @@ class Printer:
             self.field(code, "co_firstlineno")
             self.write(f".co_nlocalsplus = {len(localsplusnames)},")
             self.field(code, "co_nlocals")
-            self.write(f".co_nplaincellvars = {nplaincellvars},")
             self.write(f".co_ncellvars = {ncellvars},")
             self.write(f".co_nfreevars = {nfreevars},")
             self.write(f".co_version = {next_code_version},")