summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorMark Shannon <mark@hotpy.org>2021-01-29 13:24:55 +0000
committerGitHub <noreply@github.com>2021-01-29 13:24:55 +0000
commitd6c33fbd346765c6a8654dccacb2338006bf2b47 (patch)
tree857d7b70431dc74ca9b68e5ce1d56953f19f8d77
parent23a567c11ca36eedde0e119443c85cc16075deaf (diff)
downloadcpython-git-d6c33fbd346765c6a8654dccacb2338006bf2b47.tar.gz
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
-rw-r--r--Include/cpython/frameobject.h4
-rw-r--r--Include/funcobject.h26
-rw-r--r--Include/internal/pycore_ceval.h7
-rw-r--r--Lib/test/test_sys.py2
-rw-r--r--Objects/call.c33
-rw-r--r--Objects/frameobject.c85
-rw-r--r--Objects/funcobject.c13
-rw-r--r--Python/ceval.c130
8 files changed, 144 insertions, 156 deletions
diff --git a/Include/cpython/frameobject.h b/Include/cpython/frameobject.h
index 28170615a0..f162e2465f 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 c5cc9d261a..d7acd18c65 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 38fd681f20..a9da8b8f45 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 c4e0535948..fca05e6f88 100644
--- a/Lib/test/test_sys.py
+++ b/Lib/test/test_sys.py
@@ -1280,7 +1280,7 @@ class SizeofTest(unittest.TestCase):
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 1fb85efab6..7972693918 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 4c5eaa23d3..45a275bd90 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 e7961b3e6e..f839d7b429 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 5e2a160f0e..be9ea24454 100644
--- a/Python/ceval.c
+++ b/Python/ceval.c
@@ -3888,7 +3888,7 @@ main_loop:
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 @@ fail:
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 @@ fail: /* Jump here from prelude on failure */
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 *