diff options
author | 2021-02-01 10:42:03 +0000 | |
---|---|---|
committer | 2021-02-01 10:42:03 +0000 | |
commit | 0332e569c12d3dc97171546c6dc10e42c27de34b (patch) | |
tree | 1ef4cc33b19c2c7f24c157ffdfa61250ea2c9787 | |
parent | bpo-42504: Ensure that get_config_var('MACOSX_DEPLOYMENT_TARGET') is a string... (diff) | |
download | cpython-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.h | 4 | ||||
-rw-r--r-- | Include/eval.h | 10 | ||||
-rw-r--r-- | Include/internal/pycore_ceval.h | 11 | ||||
-rw-r--r-- | Misc/NEWS.d/next/Core and Builtins/2021-01-30-11-31-44.bpo-42990.69h_zK.rst | 5 | ||||
-rw-r--r-- | Objects/call.c | 77 | ||||
-rw-r--r-- | Objects/frameobject.c | 51 | ||||
-rw-r--r-- | Objects/funcobject.c | 4 | ||||
-rw-r--r-- | Python/bltinmodule.c | 7 | ||||
-rw-r--r-- | Python/ceval.c | 323 |
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) |