bpo-42990: Further refactoring of PyEval_ functions. (GH-24368)

* Further refactoring of PyEval_EvalCode and friends. Break into make-frame, and eval-frame parts.

* Simplify function vector call using new _PyEval_Vector.

* Remove unused internal functions: _PyEval_EvalCodeWithName and _PyEval_EvalCode.

* Don't use legacy function PyEval_EvalCodeEx.
This commit is contained in:
Mark Shannon 2021-02-01 10:42:03 +00:00 committed by GitHub
parent 49926cf2bc
commit 0332e569c1
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
9 changed files with 255 additions and 253 deletions

View File

@ -71,8 +71,8 @@ PyAPI_FUNC(PyFrameObject *) PyFrame_New(PyThreadState *, PyCodeObject *,
PyObject *, PyObject *); PyObject *, PyObject *);
/* only internal use */ /* only internal use */
PyFrameObject* _PyFrame_New_NoTrack(PyThreadState *, PyCodeObject *, PyFrameObject*
PyObject *, PyObject *, PyObject *); _PyFrame_New_NoTrack(PyThreadState *, PyFrameConstructor *, PyObject *);
/* The rest of the interface is specific for frame objects */ /* The rest of the interface is specific for frame objects */

View File

@ -18,16 +18,6 @@ PyAPI_FUNC(PyObject *) PyEval_EvalCodeEx(PyObject *co,
PyObject *kwdefs, PyObject *closure); PyObject *kwdefs, PyObject *closure);
#ifndef Py_LIMITED_API #ifndef Py_LIMITED_API
PyAPI_FUNC(PyObject *) _PyEval_EvalCodeWithName(
PyObject *co,
PyObject *globals, 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);
PyAPI_FUNC(PyObject *) _PyEval_CallTracing(PyObject *func, PyObject *args); PyAPI_FUNC(PyObject *) _PyEval_CallTracing(PyObject *func, PyObject *args);
#endif #endif

View File

@ -40,12 +40,11 @@ _PyEval_EvalFrame(PyThreadState *tstate, PyFrameObject *f, int throwflag)
return tstate->interp->eval_frame(tstate, f, throwflag); return tstate->interp->eval_frame(tstate, f, throwflag);
} }
extern PyObject *_PyEval_EvalCode( extern PyObject *
PyThreadState *tstate, _PyEval_Vector(PyThreadState *tstate,
PyFrameConstructor *desc, PyObject *locals, PyFrameConstructor *desc, PyObject *locals,
PyObject *const *args, Py_ssize_t argcount, PyObject* const* args, size_t argcount,
PyObject *const *kwnames, PyObject *const *kwargs, PyObject *kwnames);
Py_ssize_t kwcount, int kwstep);
#ifdef EXPERIMENTAL_ISOLATED_SUBINTERPRETERS #ifdef EXPERIMENTAL_ISOLATED_SUBINTERPRETERS
extern int _PyEval_ThreadsInitialized(PyInterpreterState *interp); extern int _PyEval_ThreadsInitialized(PyInterpreterState *interp);

View File

@ -0,0 +1,5 @@
Refactor the ``PyEval_`` family of functions.
* An new function ``_PyEval_Vector`` is added to simplify calls to Python from C.
* ``_PyEval_EvalCodeWithName`` is removed
* ``PyEval_EvalCodeEx`` is retained as part of the API, but is not used internally

View File

@ -328,87 +328,24 @@ PyCFunction_Call(PyObject *callable, PyObject *args, PyObject *kwargs)
/* --- PyFunction call functions ---------------------------------- */ /* --- PyFunction call functions ---------------------------------- */
static PyObject* _Py_HOT_FUNCTION
function_code_fastcall(PyThreadState *tstate, PyCodeObject *co,
PyObject *const *args, Py_ssize_t nargs,
PyFunctionObject *func)
{
assert(tstate != 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, func->func_globals, func->func_builtins, NULL);
if (f == NULL) {
return NULL;
}
PyObject **fastlocals = f->f_localsplus;
for (Py_ssize_t i = 0; i < nargs; i++) {
Py_INCREF(*args);
fastlocals[i] = *args++;
}
PyObject *result = _PyEval_EvalFrame(tstate, f, 0);
if (Py_REFCNT(f) > 1) {
Py_DECREF(f);
_PyObject_GC_TRACK(f);
}
else {
++tstate->recursion_depth;
Py_DECREF(f);
--tstate->recursion_depth;
}
return result;
}
PyObject * PyObject *
_PyFunction_Vectorcall(PyObject *func, PyObject* const* stack, _PyFunction_Vectorcall(PyObject *func, PyObject* const* stack,
size_t nargsf, PyObject *kwnames) size_t nargsf, PyObject *kwnames)
{ {
assert(PyFunction_Check(func)); assert(PyFunction_Check(func));
assert(kwnames == NULL || PyTuple_CheckExact(kwnames)); PyFrameConstructor *f = PyFunction_AS_FRAME_CONSTRUCTOR(func);
Py_ssize_t nargs = PyVectorcall_NARGS(nargsf); Py_ssize_t nargs = PyVectorcall_NARGS(nargsf);
assert(nargs >= 0); assert(nargs >= 0);
Py_ssize_t nkwargs = (kwnames == NULL) ? 0 : PyTuple_GET_SIZE(kwnames);
assert((nargs == 0 && nkwargs == 0) || stack != NULL);
/* kwnames must only contain strings and all keys must be unique */
PyThreadState *tstate = _PyThreadState_GET(); PyThreadState *tstate = _PyThreadState_GET();
PyCodeObject *co = (PyCodeObject *)PyFunction_GET_CODE(func); assert(nargs == 0 || stack != NULL);
PyObject *argdefs = PyFunction_GET_DEFAULTS(func); if (((PyCodeObject *)f->fc_code)->co_flags & CO_OPTIMIZED) {
return _PyEval_Vector(tstate, f, NULL, stack, nargs, kwnames);
if (co->co_kwonlyargcount == 0 && nkwargs == 0 && }
(co->co_flags & ~PyCF_MASK) == (CO_OPTIMIZED | CO_NEWLOCALS | CO_NOFREE)) else {
{ return _PyEval_Vector(tstate, f, f->fc_globals, stack, nargs, kwnames);
if (argdefs == NULL && co->co_argcount == nargs) {
return function_code_fastcall(tstate, co, stack, nargs, (PyFunctionObject *)func);
}
else if (nargs == 0 && argdefs != NULL
&& co->co_argcount == PyTuple_GET_SIZE(argdefs)) {
/* function called with no arguments, but all parameters have
a default value: use default values as arguments .*/
stack = _PyTuple_ITEMS(argdefs);
return function_code_fastcall(tstate, co,
stack, PyTuple_GET_SIZE(argdefs),
(PyFunctionObject *)func);
}
} }
return _PyEval_EvalCode(tstate,
PyFunction_AS_FRAME_CONSTRUCTOR(func), (PyObject *)NULL,
stack, nargs,
nkwargs ? _PyTuple_ITEMS(kwnames) : NULL,
stack + nargs,
nkwargs, 1);
} }
/* --- More complex call functions -------------------------------- */ /* --- More complex call functions -------------------------------- */
/* External interface to call any callable object. /* External interface to call any callable object.

View File

@ -816,11 +816,10 @@ frame_alloc(PyCodeObject *code)
PyFrameObject* _Py_HOT_FUNCTION PyFrameObject* _Py_HOT_FUNCTION
_PyFrame_New_NoTrack(PyThreadState *tstate, PyCodeObject *code, _PyFrame_New_NoTrack(PyThreadState *tstate, PyFrameConstructor *con, PyObject *locals)
PyObject *globals, PyObject *builtins, PyObject *locals)
{ {
#ifdef Py_DEBUG #ifdef Py_DEBUG
if (code == NULL || globals == NULL || builtins == NULL || if (con == NULL || con->fc_code == NULL ||
(locals != NULL && !PyMapping_Check(locals))) { (locals != NULL && !PyMapping_Check(locals))) {
PyErr_BadInternalCall(); PyErr_BadInternalCall();
return NULL; return NULL;
@ -829,38 +828,21 @@ _PyFrame_New_NoTrack(PyThreadState *tstate, PyCodeObject *code,
PyFrameObject *back = tstate->frame; PyFrameObject *back = tstate->frame;
PyFrameObject *f = frame_alloc(code); PyFrameObject *f = frame_alloc((PyCodeObject *)con->fc_code);
if (f == NULL) { if (f == NULL) {
return NULL; return NULL;
} }
f->f_stackdepth = 0; f->f_stackdepth = 0;
Py_INCREF(builtins); Py_INCREF(con->fc_builtins);
f->f_builtins = builtins; f->f_builtins = con->fc_builtins;
Py_XINCREF(back); Py_XINCREF(back);
f->f_back = back; f->f_back = back;
Py_INCREF(code); Py_INCREF(con->fc_code);
Py_INCREF(globals); Py_INCREF(con->fc_globals);
f->f_globals = globals; f->f_globals = con->fc_globals;
/* Most functions have CO_NEWLOCALS and CO_OPTIMIZED set. */ Py_XINCREF(locals);
if ((code->co_flags & (CO_NEWLOCALS | CO_OPTIMIZED)) == f->f_locals = locals;
(CO_NEWLOCALS | CO_OPTIMIZED))
; /* f_locals = NULL; will be set by PyFrame_FastToLocals() */
else if (code->co_flags & CO_NEWLOCALS) {
locals = PyDict_New();
if (locals == NULL) {
Py_DECREF(f);
return NULL;
}
f->f_locals = locals;
}
else {
if (locals == NULL) {
locals = globals;
}
Py_INCREF(locals);
f->f_locals = locals;
}
f->f_lasti = -1; f->f_lasti = -1;
f->f_lineno = 0; f->f_lineno = 0;
@ -875,12 +857,23 @@ _PyFrame_New_NoTrack(PyThreadState *tstate, PyCodeObject *code,
return f; return f;
} }
/* Legacy API */
PyFrameObject* PyFrameObject*
PyFrame_New(PyThreadState *tstate, PyCodeObject *code, PyFrame_New(PyThreadState *tstate, PyCodeObject *code,
PyObject *globals, PyObject *locals) PyObject *globals, PyObject *locals)
{ {
PyObject *builtins = _PyEval_BuiltinsFromGlobals(globals); PyObject *builtins = _PyEval_BuiltinsFromGlobals(globals);
PyFrameObject *f = _PyFrame_New_NoTrack(tstate, code, globals, builtins, locals); PyFrameConstructor desc = {
.fc_globals = globals,
.fc_builtins = builtins,
.fc_name = code->co_name,
.fc_qualname = code->co_name,
.fc_code = (PyObject *)code,
.fc_defaults = NULL,
.fc_kwdefaults = NULL,
.fc_closure = NULL
};
PyFrameObject *f = _PyFrame_New_NoTrack(tstate, &desc, locals);
Py_DECREF(builtins); Py_DECREF(builtins);
if (f) if (f)
_PyObject_GC_TRACK(f); _PyObject_GC_TRACK(f);

View File

@ -575,9 +575,9 @@ func_new_impl(PyTypeObject *type, PyCodeObject *code, PyObject *globals,
newfunc = (PyFunctionObject *)PyFunction_New((PyObject *)code, newfunc = (PyFunctionObject *)PyFunction_New((PyObject *)code,
globals); globals);
if (newfunc == NULL) if (newfunc == NULL) {
return NULL; return NULL;
}
if (name != Py_None) { if (name != Py_None) {
Py_INCREF(name); Py_INCREF(name);
Py_SETREF(newfunc->func_name, name); Py_SETREF(newfunc->func_name, name);

View File

@ -8,6 +8,7 @@
#include "pycore_pyerrors.h" // _PyErr_NoMemory() #include "pycore_pyerrors.h" // _PyErr_NoMemory()
#include "pycore_pystate.h" // _PyThreadState_GET() #include "pycore_pystate.h" // _PyThreadState_GET()
#include "pycore_tuple.h" // _PyTuple_FromArray() #include "pycore_tuple.h" // _PyTuple_FromArray()
#include "pycore_ceval.h" // _PyEval_Vector()
_Py_IDENTIFIER(__builtins__); _Py_IDENTIFIER(__builtins__);
_Py_IDENTIFIER(__dict__); _Py_IDENTIFIER(__dict__);
@ -219,9 +220,9 @@ builtin___build_class__(PyObject *self, PyObject *const *args, Py_ssize_t nargs,
Py_TYPE(ns)->tp_name); Py_TYPE(ns)->tp_name);
goto error; goto error;
} }
cell = PyEval_EvalCodeEx(PyFunction_GET_CODE(func), PyFunction_GET_GLOBALS(func), ns, PyFrameConstructor *f = PyFunction_AS_FRAME_CONSTRUCTOR(func);
NULL, 0, NULL, 0, NULL, 0, NULL, PyThreadState *tstate = PyThreadState_GET();
PyFunction_GET_CLOSURE(func)); cell = _PyEval_Vector(tstate, f, ns, NULL, 0, NULL);
if (cell != NULL) { if (cell != NULL) {
if (bases != orig_bases) { if (bases != orig_bases) {
if (PyMapping_SetItemString(ns, "__orig_bases__", orig_bases) < 0) { if (PyMapping_SetItemString(ns, "__orig_bases__", orig_bases) < 0) {

View File

@ -890,12 +890,27 @@ static int unpack_iterable(PyThreadState *, PyObject *, int, int, PyObject **);
PyObject * PyObject *
PyEval_EvalCode(PyObject *co, PyObject *globals, PyObject *locals) PyEval_EvalCode(PyObject *co, PyObject *globals, PyObject *locals)
{ {
return PyEval_EvalCodeEx(co, if (locals == NULL) {
globals, locals, locals = globals;
(PyObject **)NULL, 0, }
(PyObject **)NULL, 0, PyObject *builtins = _PyEval_BuiltinsFromGlobals(globals);
(PyObject **)NULL, 0, if (builtins == NULL) {
NULL, NULL); return NULL;
}
PyFrameConstructor desc = {
.fc_globals = globals,
.fc_builtins = builtins,
.fc_name = ((PyCodeObject *)co)->co_name,
.fc_qualname = ((PyCodeObject *)co)->co_name,
.fc_code = co,
.fc_defaults = NULL,
.fc_kwdefaults = NULL,
.fc_closure = NULL
};
PyThreadState *tstate = PyThreadState_GET();
PyObject *res =_PyEval_Vector(tstate, &desc, locals, NULL, 0, NULL);
Py_DECREF(builtins);
return res;
} }
@ -4343,7 +4358,7 @@ too_many_positional(PyThreadState *tstate, PyCodeObject *co,
static int static int
positional_only_passed_as_keyword(PyThreadState *tstate, PyCodeObject *co, positional_only_passed_as_keyword(PyThreadState *tstate, PyCodeObject *co,
Py_ssize_t kwcount, PyObject* const* kwnames, Py_ssize_t kwcount, PyObject* kwnames,
PyObject *qualname) PyObject *qualname)
{ {
int posonly_conflicts = 0; int posonly_conflicts = 0;
@ -4354,7 +4369,7 @@ positional_only_passed_as_keyword(PyThreadState *tstate, PyCodeObject *co,
for (int k2=0; k2<kwcount; k2++){ for (int k2=0; k2<kwcount; k2++){
/* Compare the pointers first and fallback to PyObject_RichCompareBool*/ /* Compare the pointers first and fallback to PyObject_RichCompareBool*/
PyObject* kwname = kwnames[k2]; PyObject* kwname = PyTuple_GET_ITEM(kwnames, k2);
if (kwname == posonly_name){ if (kwname == posonly_name){
if(PyList_Append(posonly_names, kwname) != 0) { if(PyList_Append(posonly_names, kwname) != 0) {
goto fail; goto fail;
@ -4403,26 +4418,21 @@ fail:
} }
/* This is gonna seem *real weird*, but if you put some other code between
PyEval_EvalFrame() and _PyEval_EvalFrameDefault() you will need to adjust
the test in the if statements in Misc/gdbinit (pystack and pystackv). */
PyObject * PyFrameObject *
_PyEval_EvalCode(PyThreadState *tstate, _PyEval_MakeFrameVector(PyThreadState *tstate,
PyFrameConstructor *con, PyObject *locals, PyFrameConstructor *con, PyObject *locals,
PyObject *const *args, Py_ssize_t argcount, PyObject *const *args, Py_ssize_t argcount,
PyObject *const *kwnames, PyObject *const *kwargs, PyObject *kwnames)
Py_ssize_t kwcount, int kwstep)
{ {
assert(is_tstate_valid(tstate)); assert(is_tstate_valid(tstate));
PyCodeObject *co = (PyCodeObject*)con->fc_code; PyCodeObject *co = (PyCodeObject*)con->fc_code;
assert(con->fc_defaults == NULL || PyTuple_CheckExact(con->fc_defaults)); 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; const Py_ssize_t total_args = co->co_argcount + co->co_kwonlyargcount;
/* Create the frame */ /* Create the frame */
PyFrameObject *f = _PyFrame_New_NoTrack(tstate, co, con->fc_globals, con->fc_builtins, locals); PyFrameObject *f = _PyFrame_New_NoTrack(tstate, con, locals);
if (f == NULL) { if (f == NULL) {
return NULL; return NULL;
} }
@ -4469,74 +4479,76 @@ _PyEval_EvalCode(PyThreadState *tstate,
SETLOCAL(total_args, u); SETLOCAL(total_args, u);
} }
/* Handle keyword arguments passed as two strided arrays */ /* Handle keyword arguments */
kwcount *= kwstep; if (kwnames != NULL) {
for (i = 0; i < kwcount; i += kwstep) { Py_ssize_t kwcount = PyTuple_GET_SIZE(kwnames);
PyObject **co_varnames; for (i = 0; i < kwcount; i++) {
PyObject *keyword = kwnames[i]; PyObject **co_varnames;
PyObject *value = kwargs[i]; PyObject *keyword = PyTuple_GET_ITEM(kwnames, i);
Py_ssize_t j; PyObject *value = args[i+argcount];
Py_ssize_t j;
if (keyword == NULL || !PyUnicode_Check(keyword)) { if (keyword == NULL || !PyUnicode_Check(keyword)) {
_PyErr_Format(tstate, PyExc_TypeError, _PyErr_Format(tstate, PyExc_TypeError,
"%U() keywords must be strings", "%U() keywords must be strings",
con->fc_qualname); con->fc_qualname);
goto fail;
}
/* Speed hack: do raw pointer compares. As names are
normally interned this should almost always hit. */
co_varnames = ((PyTupleObject *)(co->co_varnames))->ob_item;
for (j = co->co_posonlyargcount; j < total_args; j++) {
PyObject *varname = co_varnames[j];
if (varname == keyword) {
goto kw_found;
}
}
/* Slow fallback, just in case */
for (j = co->co_posonlyargcount; j < total_args; j++) {
PyObject *varname = co_varnames[j];
int cmp = PyObject_RichCompareBool( keyword, varname, Py_EQ);
if (cmp > 0) {
goto kw_found;
}
else if (cmp < 0) {
goto fail; goto fail;
} }
}
assert(j >= total_args); /* Speed hack: do raw pointer compares. As names are
if (kwdict == NULL) { normally interned this should almost always hit. */
co_varnames = ((PyTupleObject *)(co->co_varnames))->ob_item;
for (j = co->co_posonlyargcount; j < total_args; j++) {
PyObject *varname = co_varnames[j];
if (varname == keyword) {
goto kw_found;
}
}
if (co->co_posonlyargcount /* Slow fallback, just in case */
&& positional_only_passed_as_keyword(tstate, co, for (j = co->co_posonlyargcount; j < total_args; j++) {
kwcount, kwnames, PyObject *varname = co_varnames[j];
int cmp = PyObject_RichCompareBool( keyword, varname, Py_EQ);
if (cmp > 0) {
goto kw_found;
}
else if (cmp < 0) {
goto fail;
}
}
assert(j >= total_args);
if (kwdict == NULL) {
if (co->co_posonlyargcount
&& positional_only_passed_as_keyword(tstate, co,
kwcount, kwnames,
con->fc_qualname)) con->fc_qualname))
{ {
goto fail;
}
_PyErr_Format(tstate, PyExc_TypeError,
"%U() got an unexpected keyword argument '%S'",
con->fc_qualname, keyword);
goto fail; goto fail;
} }
_PyErr_Format(tstate, PyExc_TypeError, if (PyDict_SetItem(kwdict, keyword, value) == -1) {
"%U() got an unexpected keyword argument '%S'", goto fail;
con->fc_qualname, keyword); }
goto fail; continue;
}
if (PyDict_SetItem(kwdict, keyword, value) == -1) { kw_found:
goto fail; if (GETLOCAL(j) != NULL) {
} _PyErr_Format(tstate, PyExc_TypeError,
continue; "%U() got multiple values for argument '%S'",
kw_found:
if (GETLOCAL(j) != NULL) {
_PyErr_Format(tstate, PyExc_TypeError,
"%U() got multiple values for argument '%S'",
con->fc_qualname, keyword); con->fc_qualname, keyword);
goto fail; goto fail;
}
Py_INCREF(value);
SETLOCAL(j, value);
} }
Py_INCREF(value);
SETLOCAL(j, value);
} }
/* Check the number of positional arguments */ /* Check the number of positional arguments */
@ -4631,37 +4643,72 @@ _PyEval_EvalCode(PyThreadState *tstate,
freevars[PyTuple_GET_SIZE(co->co_cellvars) + i] = o; freevars[PyTuple_GET_SIZE(co->co_cellvars) + i] = o;
} }
/* Handle generator/coroutine/asynchronous generator */ return f;
if (co->co_flags & (CO_GENERATOR | CO_COROUTINE | CO_ASYNC_GENERATOR)) {
PyObject *gen;
int is_coro = co->co_flags & CO_COROUTINE;
/* Don't need to keep the reference to f_back, it will be set
* when the generator is resumed. */
Py_CLEAR(f->f_back);
/* Create a new generator that owns the ready to run frame
* and return that as the value. */
if (is_coro) {
gen = PyCoro_New(f, con->fc_name, con->fc_qualname);
} else if (co->co_flags & CO_ASYNC_GENERATOR) {
gen = PyAsyncGen_New(f, con->fc_name, con->fc_qualname);
} else {
gen = PyGen_NewWithQualName(f, con->fc_name, con->fc_qualname);
}
if (gen == NULL) {
return NULL;
}
_PyObject_GC_TRACK(f);
return gen;
}
retval = _PyEval_EvalFrame(tstate, f, 0);
fail: /* Jump here from prelude on failure */ fail: /* Jump here from prelude on failure */
/* decref'ing the frame can cause __del__ methods to get invoked,
which can call back into Python. While we're done with the
current Python frame (f), the associated C stack is still in use,
so recursion_depth must be boosted for the duration.
*/
if (Py_REFCNT(f) > 1) {
Py_DECREF(f);
_PyObject_GC_TRACK(f);
}
else {
++tstate->recursion_depth;
Py_DECREF(f);
--tstate->recursion_depth;
}
return NULL;
}
static PyObject *
make_coro(PyFrameConstructor *con, PyFrameObject *f)
{
assert (((PyCodeObject *)con->fc_code)->co_flags & (CO_GENERATOR | CO_COROUTINE | CO_ASYNC_GENERATOR));
PyObject *gen;
int is_coro = ((PyCodeObject *)con->fc_code)->co_flags & CO_COROUTINE;
/* Don't need to keep the reference to f_back, it will be set
* when the generator is resumed. */
Py_CLEAR(f->f_back);
/* Create a new generator that owns the ready to run frame
* and return that as the value. */
if (is_coro) {
gen = PyCoro_New(f, con->fc_name, con->fc_qualname);
} else if (((PyCodeObject *)con->fc_code)->co_flags & CO_ASYNC_GENERATOR) {
gen = PyAsyncGen_New(f, con->fc_name, con->fc_qualname);
} else {
gen = PyGen_NewWithQualName(f, con->fc_name, con->fc_qualname);
}
if (gen == NULL) {
return NULL;
}
_PyObject_GC_TRACK(f);
return gen;
}
PyObject *
_PyEval_Vector(PyThreadState *tstate, PyFrameConstructor *con,
PyObject *locals,
PyObject* const* args, size_t argcount,
PyObject *kwnames)
{
PyFrameObject *f = _PyEval_MakeFrameVector(
tstate, con, locals, args, argcount, kwnames);
if (f == NULL) {
return NULL;
}
if (((PyCodeObject *)con->fc_code)->co_flags & (CO_GENERATOR | CO_COROUTINE | CO_ASYNC_GENERATOR)) {
return make_coro(con, f);
}
PyObject *retval = _PyEval_EvalFrame(tstate, f, 0);
/* decref'ing the frame can cause __del__ methods to get invoked, /* decref'ing the frame can cause __del__ methods to get invoked,
which can call back into Python. While we're done with the which can call back into Python. While we're done with the
current Python frame (f), the associated C stack is still in use, current Python frame (f), the associated C stack is still in use,
@ -4681,14 +4728,13 @@ fail: /* Jump here from prelude on failure */
/* Legacy API */ /* Legacy API */
PyObject * PyObject *
_PyEval_EvalCodeWithName(PyObject *_co, PyObject *globals, PyObject *locals, PyEval_EvalCodeEx(PyObject *_co, PyObject *globals, PyObject *locals,
PyObject *const *args, Py_ssize_t argcount, PyObject *const *args, int argcount,
PyObject *const *kwnames, PyObject *const *kwargs, PyObject *const *kws, int kwcount,
Py_ssize_t kwcount, int kwstep, PyObject *const *defs, int defcount,
PyObject *const *defs, Py_ssize_t defcount, PyObject *kwdefs, PyObject *closure)
PyObject *kwdefs, PyObject *closure,
PyObject *name, PyObject *qualname)
{ {
PyObject *res;
PyObject *defaults = _PyTuple_FromArray(defs, defcount); PyObject *defaults = _PyTuple_FromArray(defs, defcount);
if (defaults == NULL) { if (defaults == NULL) {
return NULL; return NULL;
@ -4698,44 +4744,75 @@ _PyEval_EvalCodeWithName(PyObject *_co, PyObject *globals, PyObject *locals,
Py_DECREF(defaults); Py_DECREF(defaults);
return NULL; return NULL;
} }
PyCodeObject *code = (PyCodeObject *)_co;
assert ((code->co_flags & (CO_NEWLOCALS | CO_OPTIMIZED)) == 0);
if (locals == NULL) {
locals = globals;
}
PyObject *kwnames;
PyObject *const *allargs;
PyObject **newargs;
if (kwcount == 0) {
allargs = args;
kwnames = NULL;
}
else {
kwnames = PyTuple_New(kwcount);
if (kwnames == NULL) {
res = NULL;
goto fail;
}
newargs = PyMem_Malloc(sizeof(PyObject *)*(kwcount+argcount));
if (newargs == NULL) {
res = NULL;
Py_DECREF(kwnames);
goto fail;
}
for (int i = 0; i < argcount; i++) {
newargs[i] = args[i];
}
for (int i = 0; i < kwcount; i++) {
Py_INCREF(kws[2*i]);
PyTuple_SET_ITEM(kwnames, i, kws[2*i]);
newargs[argcount+i] = kws[2*i+1];
}
allargs = newargs;
}
PyObject **kwargs = PyMem_Malloc(sizeof(PyObject *)*kwcount);
if (kwargs == NULL) {
res = NULL;
Py_DECREF(kwnames);
goto fail;
}
for (int i = 0; i < kwcount; i++) {
Py_INCREF(kws[2*i]);
PyTuple_SET_ITEM(kwnames, i, kws[2*i]);
kwargs[i] = kws[2*i+1];
}
PyFrameConstructor constr = { PyFrameConstructor constr = {
.fc_globals = globals, .fc_globals = globals,
.fc_builtins = builtins, .fc_builtins = builtins,
.fc_name = name, .fc_name = ((PyCodeObject *)_co)->co_name,
.fc_qualname = qualname, .fc_qualname = ((PyCodeObject *)_co)->co_name,
.fc_code = _co, .fc_code = _co,
.fc_defaults = defaults, .fc_defaults = defaults,
.fc_kwdefaults = kwdefs, .fc_kwdefaults = kwdefs,
.fc_closure = closure .fc_closure = closure
}; };
PyThreadState *tstate = _PyThreadState_GET(); PyThreadState *tstate = _PyThreadState_GET();
PyObject *res = _PyEval_EvalCode(tstate, &constr, locals, res = _PyEval_Vector(tstate, &constr, locals,
args, argcount, allargs, argcount,
kwnames, kwargs, kwnames);
kwcount, kwstep); if (kwcount) {
Py_DECREF(kwnames);
PyMem_Free(newargs);
}
fail:
Py_DECREF(defaults); Py_DECREF(defaults);
Py_DECREF(builtins); Py_DECREF(builtins);
return res; return res;
} }
/* Legacy API */
PyObject *
PyEval_EvalCodeEx(PyObject *_co, PyObject *globals, PyObject *locals,
PyObject *const *args, int argcount,
PyObject *const *kws, int kwcount,
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,
((PyCodeObject *)_co)->co_name,
((PyCodeObject *)_co)->co_name);
}
static PyObject * static PyObject *
special_lookup(PyThreadState *tstate, PyObject *o, _Py_Identifier *id) special_lookup(PyThreadState *tstate, PyObject *o, _Py_Identifier *id)