[Python-checkins] bpo-42990: Introduce 'frame constructor' struct to simplify API for PyEval_CodeEval and friends (GH-24298)

markshannon webhook-mailer at python.org
Fri Jan 29 08:25:08 EST 2021


https://github.com/python/cpython/commit/d6c33fbd346765c6a8654dccacb2338006bf2b47
commit: d6c33fbd346765c6a8654dccacb2338006bf2b47
branch: master
author: Mark Shannon <mark at hotpy.org>
committer: markshannon <mark at hotpy.org>
date: 2021-01-29T13:24:55Z
summary:

bpo-42990: Introduce 'frame constructor' struct to simplify API for PyEval_CodeEval and friends (GH-24298)

* Introduce 'frame constructor' to simplify API for frame creation

* Embed struct using a macro to conform to PEP 7

files:
M Include/cpython/frameobject.h
M Include/funcobject.h
M Include/internal/pycore_ceval.h
M Lib/test/test_sys.py
M Objects/call.c
M Objects/frameobject.c
M Objects/funcobject.c
M Python/ceval.c

diff --git a/Include/cpython/frameobject.h b/Include/cpython/frameobject.h
index 28170615a0433..f162e2465f3a4 100644
--- a/Include/cpython/frameobject.h
+++ b/Include/cpython/frameobject.h
@@ -72,7 +72,7 @@ PyAPI_FUNC(PyFrameObject *) PyFrame_New(PyThreadState *, PyCodeObject *,
 
 /* only internal use */
 PyFrameObject* _PyFrame_New_NoTrack(PyThreadState *, PyCodeObject *,
-                                    PyObject *, PyObject *);
+                                    PyObject *, PyObject *, PyObject *);
 
 
 /* The rest of the interface is specific for frame objects */
@@ -92,3 +92,5 @@ PyAPI_FUNC(void) PyFrame_FastToLocals(PyFrameObject *);
 PyAPI_FUNC(void) _PyFrame_DebugMallocStats(FILE *out);
 
 PyAPI_FUNC(PyFrameObject *) PyFrame_GetBack(PyFrameObject *frame);
+
+PyObject *_PyEval_BuiltinsFromGlobals(PyObject *globals);
diff --git a/Include/funcobject.h b/Include/funcobject.h
index c5cc9d261a314..d7acd18c6519e 100644
--- a/Include/funcobject.h
+++ b/Include/funcobject.h
@@ -7,6 +7,21 @@
 extern "C" {
 #endif
 
+
+#define COMMON_FIELDS(PREFIX) \
+    PyObject *PREFIX ## globals; \
+    PyObject *PREFIX ## builtins; \
+    PyObject *PREFIX ## name; \
+    PyObject *PREFIX ## qualname; \
+    PyObject *PREFIX ## code;        /* A code object, the __code__ attribute */ \
+    PyObject *PREFIX ## defaults;    /* NULL or a tuple */ \
+    PyObject *PREFIX ## kwdefaults;  /* NULL or a dict */ \
+    PyObject *PREFIX ## closure;     /* NULL or a tuple of cell objects */
+
+typedef struct {
+    COMMON_FIELDS(fc_)
+} PyFrameConstructor;
+
 /* Function objects and code objects should not be confused with each other:
  *
  * Function objects are created by the execution of the 'def' statement.
@@ -20,18 +35,12 @@ extern "C" {
 
 typedef struct {
     PyObject_HEAD
-    PyObject *func_code;        /* A code object, the __code__ attribute */
-    PyObject *func_globals;     /* A dictionary (other mappings won't do) */
-    PyObject *func_defaults;    /* NULL or a tuple */
-    PyObject *func_kwdefaults;  /* NULL or a dict */
-    PyObject *func_closure;     /* NULL or a tuple of cell objects */
+    COMMON_FIELDS(func_)
     PyObject *func_doc;         /* The __doc__ attribute, can be anything */
-    PyObject *func_name;        /* The __name__ attribute, a string object */
     PyObject *func_dict;        /* The __dict__ attribute, a dict or NULL */
     PyObject *func_weakreflist; /* List of weak references */
     PyObject *func_module;      /* The __module__ attribute, can be anything */
     PyObject *func_annotations; /* Annotations, a dict or NULL */
-    PyObject *func_qualname;    /* The qualified name */
     vectorcallfunc vectorcall;
 
     /* Invariant:
@@ -84,6 +93,9 @@ PyAPI_FUNC(PyObject *) _PyFunction_Vectorcall(
 #define PyFunction_GET_ANNOTATIONS(func) \
         (((PyFunctionObject *)func) -> func_annotations)
 
+#define PyFunction_AS_FRAME_CONSTRUCTOR(func) \
+        ((PyFrameConstructor *)&((PyFunctionObject *)(func))->func_globals)
+
 /* The classmethod and staticmethod types lives here, too */
 PyAPI_DATA(PyTypeObject) PyClassMethod_Type;
 PyAPI_DATA(PyTypeObject) PyStaticMethod_Type;
diff --git a/Include/internal/pycore_ceval.h b/Include/internal/pycore_ceval.h
index 38fd681f20c45..a9da8b8f45073 100644
--- a/Include/internal/pycore_ceval.h
+++ b/Include/internal/pycore_ceval.h
@@ -42,13 +42,10 @@ _PyEval_EvalFrame(PyThreadState *tstate, PyFrameObject *f, int throwflag)
 
 extern PyObject *_PyEval_EvalCode(
     PyThreadState *tstate,
-    PyObject *_co, PyObject *globals, PyObject *locals,
+    PyFrameConstructor *desc, PyObject *locals,
     PyObject *const *args, Py_ssize_t argcount,
     PyObject *const *kwnames, PyObject *const *kwargs,
-    Py_ssize_t kwcount, int kwstep,
-    PyObject *const *defs, Py_ssize_t defcount,
-    PyObject *kwdefs, PyObject *closure,
-    PyObject *name, PyObject *qualname);
+    Py_ssize_t kwcount, int kwstep);
 
 #ifdef EXPERIMENTAL_ISOLATED_SUBINTERPRETERS
 extern int _PyEval_ThreadsInitialized(PyInterpreterState *interp);
diff --git a/Lib/test/test_sys.py b/Lib/test/test_sys.py
index c4e053594800b..fca05e6f88f30 100644
--- a/Lib/test/test_sys.py
+++ b/Lib/test/test_sys.py
@@ -1280,7 +1280,7 @@ class C(object): pass
         check(x, vsize('4Pi2c4P3ic' + CO_MAXBLOCKS*'3i' + 'P' + extras*'P'))
         # function
         def func(): pass
-        check(func, size('13P'))
+        check(func, size('14P'))
         class c():
             @staticmethod
             def foo():
diff --git a/Objects/call.c b/Objects/call.c
index 1fb85efab6169..7972693918bbb 100644
--- a/Objects/call.c
+++ b/Objects/call.c
@@ -331,16 +331,16 @@ PyCFunction_Call(PyObject *callable, PyObject *args, PyObject *kwargs)
 static PyObject* _Py_HOT_FUNCTION
 function_code_fastcall(PyThreadState *tstate, PyCodeObject *co,
                        PyObject *const *args, Py_ssize_t nargs,
-                       PyObject *globals)
+                       PyFunctionObject *func)
 {
     assert(tstate != NULL);
-    assert(globals != NULL);
+    assert(func != NULL);
 
     /* XXX Perhaps we should create a specialized
        _PyFrame_New_NoTrack() that doesn't take locals, but does
        take builtins without sanity checking them.
        */
-    PyFrameObject *f = _PyFrame_New_NoTrack(tstate, co, globals, NULL);
+    PyFrameObject *f = _PyFrame_New_NoTrack(tstate, co, func->func_globals, func->func_builtins, NULL);
     if (f == NULL) {
         return NULL;
     }
@@ -381,14 +381,13 @@ _PyFunction_Vectorcall(PyObject *func, PyObject* const* stack,
 
     PyThreadState *tstate = _PyThreadState_GET();
     PyCodeObject *co = (PyCodeObject *)PyFunction_GET_CODE(func);
-    PyObject *globals = PyFunction_GET_GLOBALS(func);
     PyObject *argdefs = PyFunction_GET_DEFAULTS(func);
 
     if (co->co_kwonlyargcount == 0 && nkwargs == 0 &&
         (co->co_flags & ~PyCF_MASK) == (CO_OPTIMIZED | CO_NEWLOCALS | CO_NOFREE))
     {
         if (argdefs == NULL && co->co_argcount == nargs) {
-            return function_code_fastcall(tstate, co, stack, nargs, globals);
+            return function_code_fastcall(tstate, co, stack, nargs, (PyFunctionObject *)func);
         }
         else if (nargs == 0 && argdefs != NULL
                  && co->co_argcount == PyTuple_GET_SIZE(argdefs)) {
@@ -397,34 +396,16 @@ _PyFunction_Vectorcall(PyObject *func, PyObject* const* stack,
             stack = _PyTuple_ITEMS(argdefs);
             return function_code_fastcall(tstate, co,
                                           stack, PyTuple_GET_SIZE(argdefs),
-                                          globals);
+                                          (PyFunctionObject *)func);
         }
     }
 
-    PyObject *kwdefs = PyFunction_GET_KW_DEFAULTS(func);
-    PyObject *closure = PyFunction_GET_CLOSURE(func);
-    PyObject *name = ((PyFunctionObject *)func) -> func_name;
-    PyObject *qualname = ((PyFunctionObject *)func) -> func_qualname;
-
-    PyObject **d;
-    Py_ssize_t nd;
-    if (argdefs != NULL) {
-        d = _PyTuple_ITEMS(argdefs);
-        nd = PyTuple_GET_SIZE(argdefs);
-        assert(nd <= INT_MAX);
-    }
-    else {
-        d = NULL;
-        nd = 0;
-    }
     return _PyEval_EvalCode(tstate,
-                (PyObject*)co, globals, (PyObject *)NULL,
+                PyFunction_AS_FRAME_CONSTRUCTOR(func), (PyObject *)NULL,
                 stack, nargs,
                 nkwargs ? _PyTuple_ITEMS(kwnames) : NULL,
                 stack + nargs,
-                nkwargs, 1,
-                d, (int)nd, kwdefs,
-                closure, name, qualname);
+                nkwargs, 1);
 }
 
 
diff --git a/Objects/frameobject.c b/Objects/frameobject.c
index 4c5eaa23d345b..45a275bd90124 100644
--- a/Objects/frameobject.c
+++ b/Objects/frameobject.c
@@ -22,7 +22,6 @@ static PyMemberDef frame_memberlist[] = {
     {NULL}      /* Sentinel */
 };
 
-
 static struct _Py_frame_state *
 get_frame_state(void)
 {
@@ -816,54 +815,12 @@ frame_alloc(PyCodeObject *code)
 }
 
 
-static inline PyObject *
-frame_get_builtins(PyFrameObject *back, PyObject *globals)
-{
-    PyObject *builtins;
-
-    if (back != NULL && back->f_globals == globals) {
-        /* If we share the globals, we share the builtins.
-           Save a lookup and a call. */
-        builtins = back->f_builtins;
-        assert(builtins != NULL);
-        Py_INCREF(builtins);
-        return builtins;
-    }
-
-    builtins = _PyDict_GetItemIdWithError(globals, &PyId___builtins__);
-    if (builtins != NULL && PyModule_Check(builtins)) {
-        builtins = PyModule_GetDict(builtins);
-        assert(builtins != NULL);
-    }
-    if (builtins != NULL) {
-        Py_INCREF(builtins);
-        return builtins;
-    }
-
-    if (PyErr_Occurred()) {
-        return NULL;
-    }
-
-    /* No builtins! Make up a minimal one.
-       Give them 'None', at least. */
-    builtins = PyDict_New();
-    if (builtins == NULL) {
-        return NULL;
-    }
-    if (PyDict_SetItemString(builtins, "None", Py_None) < 0) {
-        Py_DECREF(builtins);
-        return NULL;
-    }
-    return builtins;
-}
-
-
 PyFrameObject* _Py_HOT_FUNCTION
 _PyFrame_New_NoTrack(PyThreadState *tstate, PyCodeObject *code,
-                     PyObject *globals, PyObject *locals)
+                     PyObject *globals, PyObject *builtins, PyObject *locals)
 {
 #ifdef Py_DEBUG
-    if (code == NULL || globals == NULL || !PyDict_Check(globals) ||
+    if (code == NULL || globals == NULL || builtins == NULL ||
         (locals != NULL && !PyMapping_Check(locals))) {
         PyErr_BadInternalCall();
         return NULL;
@@ -871,18 +828,14 @@ _PyFrame_New_NoTrack(PyThreadState *tstate, PyCodeObject *code,
 #endif
 
     PyFrameObject *back = tstate->frame;
-    PyObject *builtins = frame_get_builtins(back, globals);
-    if (builtins == NULL) {
-        return NULL;
-    }
 
     PyFrameObject *f = frame_alloc(code);
     if (f == NULL) {
-        Py_DECREF(builtins);
         return NULL;
     }
 
     f->f_stackdepth = 0;
+    Py_INCREF(builtins);
     f->f_builtins = builtins;
     Py_XINCREF(back);
     f->f_back = back;
@@ -902,8 +855,9 @@ _PyFrame_New_NoTrack(PyThreadState *tstate, PyCodeObject *code,
         f->f_locals = locals;
     }
     else {
-        if (locals == NULL)
+        if (locals == NULL) {
             locals = globals;
+        }
         Py_INCREF(locals);
         f->f_locals = locals;
     }
@@ -925,7 +879,9 @@ PyFrameObject*
 PyFrame_New(PyThreadState *tstate, PyCodeObject *code,
             PyObject *globals, PyObject *locals)
 {
-    PyFrameObject *f = _PyFrame_New_NoTrack(tstate, code, globals, locals);
+    PyObject *builtins = _PyEval_BuiltinsFromGlobals(globals);
+    PyFrameObject *f = _PyFrame_New_NoTrack(tstate, code, globals, builtins, locals);
+    Py_DECREF(builtins);
     if (f)
         _PyObject_GC_TRACK(f);
     return f;
@@ -1223,3 +1179,28 @@ PyFrame_GetBack(PyFrameObject *frame)
     Py_XINCREF(back);
     return back;
 }
+
+PyObject *_PyEval_BuiltinsFromGlobals(PyObject *globals) {
+    PyObject *builtins = _PyDict_GetItemIdWithError(globals, &PyId___builtins__);
+    if (builtins) {
+        if (PyModule_Check(builtins)) {
+            builtins = PyModule_GetDict(builtins);
+            assert(builtins != NULL);
+        }
+    }
+    if (builtins == NULL) {
+        if (PyErr_Occurred()) {
+            return NULL;
+        }
+        /* No builtins!              Make up a minimal one
+            Give them 'None', at least. */
+        builtins = PyDict_New();
+        if (builtins == NULL ||
+            PyDict_SetItemString(
+                builtins, "None", Py_None) < 0)
+            return NULL;
+    }
+    else
+        Py_INCREF(builtins);
+    return builtins;
+}
diff --git a/Objects/funcobject.c b/Objects/funcobject.c
index e7961b3e6eb4b..f839d7b429e0b 100644
--- a/Objects/funcobject.c
+++ b/Objects/funcobject.c
@@ -3,6 +3,7 @@
 
 #include "Python.h"
 #include "pycore_object.h"
+#include "frameobject.h"
 #include "code.h"
 #include "structmember.h"         // PyMemberDef
 
@@ -40,8 +41,14 @@ PyFunction_NewWithQualName(PyObject *code, PyObject *globals, PyObject *qualname
     op->func_weakreflist = NULL;
     Py_INCREF(code);
     op->func_code = code;
+    assert(globals != NULL);
     Py_INCREF(globals);
     op->func_globals = globals;
+    PyObject *builtins = _PyEval_BuiltinsFromGlobals(globals);
+    if (builtins == NULL) {
+        return NULL;
+    }
+    op->func_builtins = builtins;
     op->func_name = ((PyCodeObject *)code)->co_name;
     Py_INCREF(op->func_name);
     op->func_defaults = NULL; /* No default arguments */
@@ -592,15 +599,16 @@ func_clear(PyFunctionObject *op)
 {
     Py_CLEAR(op->func_code);
     Py_CLEAR(op->func_globals);
-    Py_CLEAR(op->func_module);
+    Py_CLEAR(op->func_builtins);
     Py_CLEAR(op->func_name);
+    Py_CLEAR(op->func_qualname);
+    Py_CLEAR(op->func_module);
     Py_CLEAR(op->func_defaults);
     Py_CLEAR(op->func_kwdefaults);
     Py_CLEAR(op->func_doc);
     Py_CLEAR(op->func_dict);
     Py_CLEAR(op->func_closure);
     Py_CLEAR(op->func_annotations);
-    Py_CLEAR(op->func_qualname);
     return 0;
 }
 
@@ -627,6 +635,7 @@ func_traverse(PyFunctionObject *f, visitproc visit, void *arg)
 {
     Py_VISIT(f->func_code);
     Py_VISIT(f->func_globals);
+    Py_VISIT(f->func_builtins);
     Py_VISIT(f->func_module);
     Py_VISIT(f->func_defaults);
     Py_VISIT(f->func_kwdefaults);
diff --git a/Python/ceval.c b/Python/ceval.c
index 5e2a160f0ed35..be9ea24454768 100644
--- a/Python/ceval.c
+++ b/Python/ceval.c
@@ -3888,7 +3888,7 @@ _PyEval_EvalFrameDefault(PyThreadState *tstate, PyFrameObject *f, int throwflag)
 
             if (oparg & 0x08) {
                 assert(PyTuple_CheckExact(TOP()));
-                func ->func_closure = POP();
+                func->func_closure = POP();
             }
             if (oparg & 0x04) {
                 assert(PyTuple_CheckExact(TOP()));
@@ -4233,7 +4233,7 @@ missing_arguments(PyThreadState *tstate, PyCodeObject *co,
 
 static void
 too_many_positional(PyThreadState *tstate, PyCodeObject *co,
-                    Py_ssize_t given, Py_ssize_t defcount,
+                    Py_ssize_t given, PyObject *defaults,
                     PyObject **fastlocals, PyObject *qualname)
 {
     int plural;
@@ -4249,6 +4249,7 @@ too_many_positional(PyThreadState *tstate, PyCodeObject *co,
             kwonly_given++;
         }
     }
+    Py_ssize_t defcount = defaults == NULL ? 0 : PyTuple_GET_SIZE(defaults);
     if (defcount) {
         Py_ssize_t atleast = co_argcount - defcount;
         plural = 1;
@@ -4356,41 +4357,20 @@ positional_only_passed_as_keyword(PyThreadState *tstate, PyCodeObject *co,
 
 PyObject *
 _PyEval_EvalCode(PyThreadState *tstate,
-           PyObject *_co, PyObject *globals, PyObject *locals,
+           PyFrameConstructor *con, PyObject *locals,
            PyObject *const *args, Py_ssize_t argcount,
            PyObject *const *kwnames, PyObject *const *kwargs,
-           Py_ssize_t kwcount, int kwstep,
-           PyObject *const *defs, Py_ssize_t defcount,
-           PyObject *kwdefs, PyObject *closure,
-           PyObject *name, PyObject *qualname)
+           Py_ssize_t kwcount, int kwstep)
 {
     assert(is_tstate_valid(tstate));
 
-    PyCodeObject *co = (PyCodeObject*)_co;
-
-    if (!name) {
-        name = co->co_name;
-    }
-    assert(name != NULL);
-    assert(PyUnicode_Check(name));
-
-    if (!qualname) {
-        qualname = name;
-    }
-    assert(qualname != NULL);
-    assert(PyUnicode_Check(qualname));
-
+    PyCodeObject *co = (PyCodeObject*)con->fc_code;
+    assert(con->fc_defaults == NULL || PyTuple_CheckExact(con->fc_defaults));
     PyObject *retval = NULL;
     const Py_ssize_t total_args = co->co_argcount + co->co_kwonlyargcount;
 
-    if (globals == NULL) {
-        _PyErr_SetString(tstate, PyExc_SystemError,
-                         "PyEval_EvalCodeEx: NULL globals");
-        return NULL;
-    }
-
     /* Create the frame */
-    PyFrameObject *f = _PyFrame_New_NoTrack(tstate, co, globals, locals);
+    PyFrameObject *f = _PyFrame_New_NoTrack(tstate, co, con->fc_globals, con->fc_builtins, locals);
     if (f == NULL) {
         return NULL;
     }
@@ -4448,7 +4428,7 @@ _PyEval_EvalCode(PyThreadState *tstate,
         if (keyword == NULL || !PyUnicode_Check(keyword)) {
             _PyErr_Format(tstate, PyExc_TypeError,
                           "%U() keywords must be strings",
-                          qualname);
+                          con->fc_qualname);
             goto fail;
         }
 
@@ -4480,14 +4460,14 @@ _PyEval_EvalCode(PyThreadState *tstate,
             if (co->co_posonlyargcount
                 && positional_only_passed_as_keyword(tstate, co,
                                                      kwcount, kwnames,
-                                                     qualname))
+                                                     con->fc_qualname))
             {
                 goto fail;
             }
 
             _PyErr_Format(tstate, PyExc_TypeError,
                           "%U() got an unexpected keyword argument '%S'",
-                          qualname, keyword);
+                          con->fc_qualname, keyword);
             goto fail;
         }
 
@@ -4500,7 +4480,7 @@ _PyEval_EvalCode(PyThreadState *tstate,
         if (GETLOCAL(j) != NULL) {
             _PyErr_Format(tstate, PyExc_TypeError,
                           "%U() got multiple values for argument '%S'",
-                          qualname, keyword);
+                          con->fc_qualname, keyword);
             goto fail;
         }
         Py_INCREF(value);
@@ -4509,13 +4489,14 @@ _PyEval_EvalCode(PyThreadState *tstate,
 
     /* Check the number of positional arguments */
     if ((argcount > co->co_argcount) && !(co->co_flags & CO_VARARGS)) {
-        too_many_positional(tstate, co, argcount, defcount, fastlocals,
-                            qualname);
+        too_many_positional(tstate, co, argcount, con->fc_defaults, fastlocals,
+                            con->fc_qualname);
         goto fail;
     }
 
     /* Add missing positional arguments (copy default values from defs) */
     if (argcount < co->co_argcount) {
+        Py_ssize_t defcount = con->fc_defaults == NULL ? 0 : PyTuple_GET_SIZE(con->fc_defaults);
         Py_ssize_t m = co->co_argcount - defcount;
         Py_ssize_t missing = 0;
         for (i = argcount; i < m; i++) {
@@ -4525,18 +4506,21 @@ _PyEval_EvalCode(PyThreadState *tstate,
         }
         if (missing) {
             missing_arguments(tstate, co, missing, defcount, fastlocals,
-                              qualname);
+                              con->fc_qualname);
             goto fail;
         }
         if (n > m)
             i = n - m;
         else
             i = 0;
-        for (; i < defcount; i++) {
-            if (GETLOCAL(m+i) == NULL) {
-                PyObject *def = defs[i];
-                Py_INCREF(def);
-                SETLOCAL(m+i, def);
+        if (defcount) {
+            PyObject **defs = &PyTuple_GET_ITEM(con->fc_defaults, 0);
+            for (; i < defcount; i++) {
+                if (GETLOCAL(m+i) == NULL) {
+                    PyObject *def = defs[i];
+                    Py_INCREF(def);
+                    SETLOCAL(m+i, def);
+                }
             }
         }
     }
@@ -4548,8 +4532,8 @@ _PyEval_EvalCode(PyThreadState *tstate,
             if (GETLOCAL(i) != NULL)
                 continue;
             PyObject *varname = PyTuple_GET_ITEM(co->co_varnames, i);
-            if (kwdefs != NULL) {
-                PyObject *def = PyDict_GetItemWithError(kwdefs, varname);
+            if (con->fc_kwdefaults != NULL) {
+                PyObject *def = PyDict_GetItemWithError(con->fc_kwdefaults, varname);
                 if (def) {
                     Py_INCREF(def);
                     SETLOCAL(i, def);
@@ -4563,7 +4547,7 @@ _PyEval_EvalCode(PyThreadState *tstate,
         }
         if (missing) {
             missing_arguments(tstate, co, missing, -1, fastlocals,
-                              qualname);
+                              con->fc_qualname);
             goto fail;
         }
     }
@@ -4590,7 +4574,7 @@ _PyEval_EvalCode(PyThreadState *tstate,
 
     /* Copy closure variables to free variables */
     for (i = 0; i < PyTuple_GET_SIZE(co->co_freevars); ++i) {
-        PyObject *o = PyTuple_GET_ITEM(closure, i);
+        PyObject *o = PyTuple_GET_ITEM(con->fc_closure, i);
         Py_INCREF(o);
         freevars[PyTuple_GET_SIZE(co->co_cellvars) + i] = o;
     }
@@ -4607,11 +4591,11 @@ _PyEval_EvalCode(PyThreadState *tstate,
         /* Create a new generator that owns the ready to run frame
          * and return that as the value. */
         if (is_coro) {
-            gen = PyCoro_New(f, name, qualname);
+            gen = PyCoro_New(f, con->fc_name, con->fc_qualname);
         } else if (co->co_flags & CO_ASYNC_GENERATOR) {
-            gen = PyAsyncGen_New(f, name, qualname);
+            gen = PyAsyncGen_New(f, con->fc_name, con->fc_qualname);
         } else {
-            gen = PyGen_NewWithQualName(f, name, qualname);
+            gen = PyGen_NewWithQualName(f, con->fc_name, con->fc_qualname);
         }
         if (gen == NULL) {
             return NULL;
@@ -4643,7 +4627,7 @@ _PyEval_EvalCode(PyThreadState *tstate,
     return retval;
 }
 
-
+/* Legacy API */
 PyObject *
 _PyEval_EvalCodeWithName(PyObject *_co, PyObject *globals, PyObject *locals,
            PyObject *const *args, Py_ssize_t argcount,
@@ -4653,16 +4637,36 @@ _PyEval_EvalCodeWithName(PyObject *_co, PyObject *globals, PyObject *locals,
            PyObject *kwdefs, PyObject *closure,
            PyObject *name, PyObject *qualname)
 {
+    PyObject *defaults = _PyTuple_FromArray(defs, defcount);
+    if (defaults == NULL) {
+        return NULL;
+    }
+    PyObject *builtins = _PyEval_BuiltinsFromGlobals(globals);
+    if (builtins == NULL) {
+        Py_DECREF(defaults);
+        return NULL;
+    }
+    PyFrameConstructor constr = {
+        .fc_globals = globals,
+        .fc_builtins = builtins,
+        .fc_name = name,
+        .fc_qualname = qualname,
+        .fc_code = _co,
+        .fc_defaults = defaults,
+        .fc_kwdefaults = kwdefs,
+        .fc_closure = closure
+    };
     PyThreadState *tstate = _PyThreadState_GET();
-    return _PyEval_EvalCode(tstate, _co, globals, locals,
-               args, argcount,
-               kwnames, kwargs,
-               kwcount, kwstep,
-               defs, defcount,
-               kwdefs, closure,
-               name, qualname);
+    PyObject *res = _PyEval_EvalCode(tstate, &constr, locals,
+                                    args, argcount,
+                                    kwnames, kwargs,
+                                    kwcount, kwstep);
+    Py_DECREF(defaults);
+    Py_DECREF(builtins);
+    return res;
 }
 
+/* Legacy API */
 PyObject *
 PyEval_EvalCodeEx(PyObject *_co, PyObject *globals, PyObject *locals,
                   PyObject *const *args, int argcount,
@@ -4670,13 +4674,15 @@ PyEval_EvalCodeEx(PyObject *_co, PyObject *globals, PyObject *locals,
                   PyObject *const *defs, int defcount,
                   PyObject *kwdefs, PyObject *closure)
 {
-    return _PyEval_EvalCodeWithName(_co, globals, locals,
-                                    args, argcount,
-                                    kws, kws != NULL ? kws + 1 : NULL,
-                                    kwcount, 2,
-                                    defs, defcount,
-                                    kwdefs, closure,
-                                    NULL, NULL);
+    return _PyEval_EvalCodeWithName(
+        _co, globals, locals,
+        args, argcount,
+        kws, kws != NULL ? kws + 1 : NULL,
+        kwcount, 2,
+        defs, defcount,
+        kwdefs, closure,
+        ((PyCodeObject *)_co)->co_name,
+        ((PyCodeObject *)_co)->co_name);
 }
 
 static PyObject *



More information about the Python-checkins mailing list