aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorMark Shannon <mark@hotpy.org>2021-02-01 10:42:03 +0000
committerGitHub <noreply@github.com>2021-02-01 10:42:03 +0000
commit0332e569c12d3dc97171546c6dc10e42c27de34b (patch)
tree1ef4cc33b19c2c7f24c157ffdfa61250ea2c9787
parentbpo-42504: Ensure that get_config_var('MACOSX_DEPLOYMENT_TARGET') is a string... (diff)
downloadcpython-0332e569c12d3dc97171546c6dc10e42c27de34b.tar.gz
cpython-0332e569c12d3dc97171546c6dc10e42c27de34b.tar.bz2
cpython-0332e569c12d3dc97171546c6dc10e42c27de34b.zip
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.
-rw-r--r--Include/cpython/frameobject.h4
-rw-r--r--Include/eval.h10
-rw-r--r--Include/internal/pycore_ceval.h11
-rw-r--r--Misc/NEWS.d/next/Core and Builtins/2021-01-30-11-31-44.bpo-42990.69h_zK.rst5
-rw-r--r--Objects/call.c77
-rw-r--r--Objects/frameobject.c51
-rw-r--r--Objects/funcobject.c4
-rw-r--r--Python/bltinmodule.c7
-rw-r--r--Python/ceval.c323
9 files changed, 247 insertions, 245 deletions
diff --git a/Include/cpython/frameobject.h b/Include/cpython/frameobject.h
index f162e2465f3..5a19c006d91 100644
--- a/Include/cpython/frameobject.h
+++ b/Include/cpython/frameobject.h
@@ -71,8 +71,8 @@ PyAPI_FUNC(PyFrameObject *) PyFrame_New(PyThreadState *, PyCodeObject *,
PyObject *, PyObject *);
/* only internal use */
-PyFrameObject* _PyFrame_New_NoTrack(PyThreadState *, PyCodeObject *,
- PyObject *, PyObject *, PyObject *);
+PyFrameObject*
+_PyFrame_New_NoTrack(PyThreadState *, PyFrameConstructor *, PyObject *);
/* The rest of the interface is specific for frame objects */
diff --git a/Include/eval.h b/Include/eval.h
index 2c1c2d0549a..eda28df8f65 100644
--- a/Include/eval.h
+++ b/Include/eval.h
@@ -18,16 +18,6 @@ PyAPI_FUNC(PyObject *) PyEval_EvalCodeEx(PyObject *co,
PyObject *kwdefs, PyObject *closure);
#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);
#endif
diff --git a/Include/internal/pycore_ceval.h b/Include/internal/pycore_ceval.h
index a9da8b8f450..0491d48a789 100644
--- a/Include/internal/pycore_ceval.h
+++ b/Include/internal/pycore_ceval.h
@@ -40,12 +40,11 @@ _PyEval_EvalFrame(PyThreadState *tstate, PyFrameObject *f, int throwflag)
return tstate->interp->eval_frame(tstate, f, throwflag);
}
-extern PyObject *_PyEval_EvalCode(
- PyThreadState *tstate,
- PyFrameConstructor *desc, PyObject *locals,
- PyObject *const *args, Py_ssize_t argcount,
- PyObject *const *kwnames, PyObject *const *kwargs,
- Py_ssize_t kwcount, int kwstep);
+extern PyObject *
+_PyEval_Vector(PyThreadState *tstate,
+ PyFrameConstructor *desc, PyObject *locals,
+ PyObject* const* args, size_t argcount,
+ PyObject *kwnames);
#ifdef EXPERIMENTAL_ISOLATED_SUBINTERPRETERS
extern int _PyEval_ThreadsInitialized(PyInterpreterState *interp);
diff --git a/Misc/NEWS.d/next/Core and Builtins/2021-01-30-11-31-44.bpo-42990.69h_zK.rst b/Misc/NEWS.d/next/Core and Builtins/2021-01-30-11-31-44.bpo-42990.69h_zK.rst
new file mode 100644
index 00000000000..8ac39713e11
--- /dev/null
+++ b/Misc/NEWS.d/next/Core and Builtins/2021-01-30-11-31-44.bpo-42990.69h_zK.rst
@@ -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
diff --git a/Objects/call.c b/Objects/call.c
index 7972693918b..960c37e1961 100644
--- a/Objects/call.c
+++ b/Objects/call.c
@@ -328,87 +328,24 @@ PyCFunction_Call(PyObject *callable, PyObject *args, PyObject *kwargs)
/* --- 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 *
_PyFunction_Vectorcall(PyObject *func, PyObject* const* stack,
size_t nargsf, PyObject *kwnames)
{
assert(PyFunction_Check(func));
- assert(kwnames == NULL || PyTuple_CheckExact(kwnames));
-
+ PyFrameConstructor *f = PyFunction_AS_FRAME_CONSTRUCTOR(func);
Py_ssize_t nargs = PyVectorcall_NARGS(nargsf);
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();
- PyCodeObject *co = (PyCodeObject *)PyFunction_GET_CODE(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, (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);
- }
+ assert(nargs == 0 || stack != NULL);
+ if (((PyCodeObject *)f->fc_code)->co_flags & CO_OPTIMIZED) {
+ return _PyEval_Vector(tstate, f, NULL, stack, nargs, kwnames);
+ }
+ else {
+ return _PyEval_Vector(tstate, f, f->fc_globals, stack, nargs, kwnames);
}
-
- 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 -------------------------------- */
/* External interface to call any callable object.
diff --git a/Objects/frameobject.c b/Objects/frameobject.c
index 45a275bd901..57105e1a9eb 100644
--- a/Objects/frameobject.c
+++ b/Objects/frameobject.c
@@ -816,11 +816,10 @@ frame_alloc(PyCodeObject *code)
PyFrameObject* _Py_HOT_FUNCTION
-_PyFrame_New_NoTrack(PyThreadState *tstate, PyCodeObject *code,
- PyObject *globals, PyObject *builtins, PyObject *locals)
+_PyFrame_New_NoTrack(PyThreadState *tstate, PyFrameConstructor *con, PyObject *locals)
{
#ifdef Py_DEBUG
- if (code == NULL || globals == NULL || builtins == NULL ||
+ if (con == NULL || con->fc_code == NULL ||
(locals != NULL && !PyMapping_Check(locals))) {
PyErr_BadInternalCall();
return NULL;
@@ -829,38 +828,21 @@ _PyFrame_New_NoTrack(PyThreadState *tstate, PyCodeObject *code,
PyFrameObject *back = tstate->frame;
- PyFrameObject *f = frame_alloc(code);
+ PyFrameObject *f = frame_alloc((PyCodeObject *)con->fc_code);
if (f == NULL) {
return NULL;
}
f->f_stackdepth = 0;
- Py_INCREF(builtins);
- f->f_builtins = builtins;
+ Py_INCREF(con->fc_builtins);
+ f->f_builtins = con->fc_builtins;
Py_XINCREF(back);
f->f_back = back;
- Py_INCREF(code);
- Py_INCREF(globals);
- f->f_globals = globals;
- /* Most functions have CO_NEWLOCALS and CO_OPTIMIZED set. */
- if ((code->co_flags & (CO_NEWLOCALS | CO_OPTIMIZED)) ==
- (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;
- }
+ Py_INCREF(con->fc_code);
+ Py_INCREF(con->fc_globals);
+ f->f_globals = con->fc_globals;
+ Py_XINCREF(locals);
+ f->f_locals = locals;
f->f_lasti = -1;
f->f_lineno = 0;
@@ -875,12 +857,23 @@ _PyFrame_New_NoTrack(PyThreadState *tstate, PyCodeObject *code,
return f;
}
+/* Legacy API */
PyFrameObject*
PyFrame_New(PyThreadState *tstate, PyCodeObject *code,
PyObject *globals, PyObject *locals)
{
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);
if (f)
_PyObject_GC_TRACK(f);
diff --git a/Objects/funcobject.c b/Objects/funcobject.c
index f839d7b429e..b331c4c4d6e 100644
--- a/Objects/funcobject.c
+++ b/Objects/funcobject.c
@@ -575,9 +575,9 @@ func_new_impl(PyTypeObject *type, PyCodeObject *code, PyObject *globals,
newfunc = (PyFunctionObject *)PyFunction_New((PyObject *)code,
globals);
- if (newfunc == NULL)
+ if (newfunc == NULL) {
return NULL;
-
+ }
if (name != Py_None) {
Py_INCREF(name);
Py_SETREF(newfunc->func_name, name);
diff --git a/Python/bltinmodule.c b/Python/bltinmodule.c
index 352fb83d55e..8c4e6e5107f 100644
--- a/Python/bltinmodule.c
+++ b/Python/bltinmodule.c
@@ -8,6 +8,7 @@
#include "pycore_pyerrors.h" // _PyErr_NoMemory()
#include "pycore_pystate.h" // _PyThreadState_GET()
#include "pycore_tuple.h" // _PyTuple_FromArray()
+#include "pycore_ceval.h" // _PyEval_Vector()
_Py_IDENTIFIER(__builtins__);
_Py_IDENTIFIER(__dict__);
@@ -219,9 +220,9 @@ builtin___build_class__(PyObject *self, PyObject *const *args, Py_ssize_t nargs,
Py_TYPE(ns)->tp_name);
goto error;
}
- cell = PyEval_EvalCodeEx(PyFunction_GET_CODE(func), PyFunction_GET_GLOBALS(func), ns,
- NULL, 0, NULL, 0, NULL, 0, NULL,
- PyFunction_GET_CLOSURE(func));
+ PyFrameConstructor *f = PyFunction_AS_FRAME_CONSTRUCTOR(func);
+ PyThreadState *tstate = PyThreadState_GET();
+ cell = _PyEval_Vector(tstate, f, ns, NULL, 0, NULL);
if (cell != NULL) {
if (bases != orig_bases) {
if (PyMapping_SetItemString(ns, "__orig_bases__", orig_bases) < 0) {
diff --git a/Python/ceval.c b/Python/ceval.c
index 3aa2aa2c9bc..3b67a6b79bf 100644
--- a/Python/ceval.c
+++ b/Python/ceval.c
@@ -890,12 +890,27 @@ static int unpack_iterable(PyThreadState *, PyObject *, int, int, PyObject **);
PyObject *
PyEval_EvalCode(PyObject *co, PyObject *globals, PyObject *locals)
{
- return PyEval_EvalCodeEx(co,
- globals, locals,
- (PyObject **)NULL, 0,
- (PyObject **)NULL, 0,
- (PyObject **)NULL, 0,
- NULL, NULL);
+ if (locals == NULL) {
+ locals = globals;
+ }
+ PyObject *builtins = _PyEval_BuiltinsFromGlobals(globals);
+ if (builtins == 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
positional_only_passed_as_keyword(PyThreadState *tstate, PyCodeObject *co,
- Py_ssize_t kwcount, PyObject* const* kwnames,
+ Py_ssize_t kwcount, PyObject* kwnames,
PyObject *qualname)
{
int posonly_conflicts = 0;
@@ -4354,7 +4369,7 @@ positional_only_passed_as_keyword(PyThreadState *tstate, PyCodeObject *co,
for (int k2=0; k2<kwcount; k2++){
/* 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(PyList_Append(posonly_names, kwname) != 0) {
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 *
-_PyEval_EvalCode(PyThreadState *tstate,
+PyFrameObject *
+_PyEval_MakeFrameVector(PyThreadState *tstate,
PyFrameConstructor *con, PyObject *locals,
PyObject *const *args, Py_ssize_t argcount,
- PyObject *const *kwnames, PyObject *const *kwargs,
- Py_ssize_t kwcount, int kwstep)
+ PyObject *kwnames)
{
assert(is_tstate_valid(tstate));
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;
/* 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) {
return NULL;
}
@@ -4469,74 +4479,76 @@ _PyEval_EvalCode(PyThreadState *tstate,
SETLOCAL(total_args, u);
}
- /* Handle keyword arguments passed as two strided arrays */
- kwcount *= kwstep;
- for (i = 0; i < kwcount; i += kwstep) {
- PyObject **co_varnames;
- PyObject *keyword = kwnames[i];
- PyObject *value = kwargs[i];
- Py_ssize_t j;
+ /* Handle keyword arguments */
+ if (kwnames != NULL) {
+ Py_ssize_t kwcount = PyTuple_GET_SIZE(kwnames);
+ for (i = 0; i < kwcount; i++) {
+ PyObject **co_varnames;
+ PyObject *keyword = PyTuple_GET_ITEM(kwnames, i);
+ PyObject *value = args[i+argcount];
+ Py_ssize_t j;
- if (keyword == NULL || !PyUnicode_Check(keyword)) {
- _PyErr_Format(tstate, PyExc_TypeError,
- "%U() keywords must be strings",
+ if (keyword == NULL || !PyUnicode_Check(keyword)) {
+ _PyErr_Format(tstate, PyExc_TypeError,
+ "%U() keywords must be strings",
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;
+ goto fail;
}
- }
- /* 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;
+ /* 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;
+ }
}
- else if (cmp < 0) {
- goto fail;
+
+ /* 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;
+ }
}
- }
- assert(j >= total_args);
- if (kwdict == NULL) {
+ assert(j >= total_args);
+ if (kwdict == NULL) {
- if (co->co_posonlyargcount
- && positional_only_passed_as_keyword(tstate, co,
- kwcount, kwnames,
+ if (co->co_posonlyargcount
+ && positional_only_passed_as_keyword(tstate, co,
+ kwcount, kwnames,
con->fc_qualname))
- {
- goto fail;
- }
+ {
+ goto fail;
+ }
- _PyErr_Format(tstate, PyExc_TypeError,
- "%U() got an unexpected keyword argument '%S'",
+ _PyErr_Format(tstate, PyExc_TypeError,
+ "%U() got an unexpected keyword argument '%S'",
con->fc_qualname, keyword);
- goto fail;
- }
+ goto fail;
+ }
- if (PyDict_SetItem(kwdict, keyword, value) == -1) {
- goto fail;
- }
- continue;
+ if (PyDict_SetItem(kwdict, keyword, value) == -1) {
+ goto fail;
+ }
+ continue;
- kw_found:
- if (GETLOCAL(j) != NULL) {
- _PyErr_Format(tstate, PyExc_TypeError,
- "%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);
- goto fail;
+ goto fail;
+ }
+ Py_INCREF(value);
+ SETLOCAL(j, value);
}
- Py_INCREF(value);
- SETLOCAL(j, value);
}
/* Check the number of positional arguments */
@@ -4631,36 +4643,71 @@ _PyEval_EvalCode(PyThreadState *tstate,
freevars[PyTuple_GET_SIZE(co->co_cellvars) + i] = o;
}
- /* Handle generator/coroutine/asynchronous generator */
- if (co->co_flags & (CO_GENERATOR | CO_COROUTINE | CO_ASYNC_GENERATOR)) {
- PyObject *gen;
- int is_coro = co->co_flags & CO_COROUTINE;
+ return f;
+
+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);
+ /* 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) {
+ /* 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) {
+ } else if (((PyCodeObject *)con->fc_code)->co_flags & CO_ASYNC_GENERATOR) {
gen = PyAsyncGen_New(f, con->fc_name, con->fc_qualname);
- } else {
+ } else {
gen = PyGen_NewWithQualName(f, con->fc_name, con->fc_qualname);
- }
- if (gen == NULL) {
- return NULL;
- }
-
- _PyObject_GC_TRACK(f);
-
- return gen;
+ }
+ if (gen == NULL) {
+ return NULL;
}
- retval = _PyEval_EvalFrame(tstate, f, 0);
+ _PyObject_GC_TRACK(f);
-fail: /* Jump here from prelude on failure */
+ 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,
which can call back into Python. While we're done with the
@@ -4681,14 +4728,13 @@ fail: /* Jump here from prelude on failure */
/* Legacy API */
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)
+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)
{
+ PyObject *res;
PyObject *defaults = _PyTuple_FromArray(defs, defcount);
if (defaults == NULL) {
return NULL;
@@ -4698,44 +4744,75 @@ _PyEval_EvalCodeWithName(PyObject *_co, PyObject *globals, PyObject *locals,
Py_DECREF(defaults);
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 = {
.fc_globals = globals,
.fc_builtins = builtins,
- .fc_name = name,
- .fc_qualname = qualname,
+ .fc_name = ((PyCodeObject *)_co)->co_name,
+ .fc_qualname = ((PyCodeObject *)_co)->co_name,
.fc_code = _co,
.fc_defaults = defaults,
.fc_kwdefaults = kwdefs,
.fc_closure = closure
};
PyThreadState *tstate = _PyThreadState_GET();
- PyObject *res = _PyEval_EvalCode(tstate, &constr, locals,
- args, argcount,
- kwnames, kwargs,
- kwcount, kwstep);
+ res = _PyEval_Vector(tstate, &constr, locals,
+ allargs, argcount,
+ kwnames);
+ if (kwcount) {
+ Py_DECREF(kwnames);
+ PyMem_Free(newargs);
+ }
+fail:
Py_DECREF(defaults);
Py_DECREF(builtins);
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 *
special_lookup(PyThreadState *tstate, PyObject *o, _Py_Identifier *id)