From b5e170f127b57d5b0a4fb58f316acd6191509dce Mon Sep 17 00:00:00 2001 From: Victor Stinner Date: Sat, 16 Nov 2019 01:03:22 +0100 Subject: [PATCH] bpo-38644: Add _PyEval_EvalCode() (GH-17183) _PyFunction_Vectorcall() now pass tstate to function calls. --- Include/internal/pycore_ceval.h | 10 ++++++ Objects/call.c | 59 +++++++++++++++++---------------- Python/ceval.c | 28 +++++++++++++--- 3 files changed, 65 insertions(+), 32 deletions(-) diff --git a/Include/internal/pycore_ceval.h b/Include/internal/pycore_ceval.h index 7adb87214a0..857fc0b2524 100644 --- a/Include/internal/pycore_ceval.h +++ b/Include/internal/pycore_ceval.h @@ -43,6 +43,16 @@ _PyEval_EvalFrame(PyThreadState *tstate, struct _frame *f, int throwflag) return tstate->interp->eval_frame(f, throwflag); } +extern PyObject *_PyEval_EvalCode( + PyThreadState *tstate, + 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); + #ifdef __cplusplus } #endif diff --git a/Objects/call.c b/Objects/call.c index ae08d182446..0f8cb5aa246 100644 --- a/Objects/call.c +++ b/Objects/call.c @@ -302,13 +302,12 @@ PyCFunction_Call(PyObject *callable, PyObject *args, PyObject *kwargs) /* --- PyFunction call functions ---------------------------------- */ static PyObject* _Py_HOT_FUNCTION -function_code_fastcall(PyCodeObject *co, PyObject *const *args, Py_ssize_t nargs, +function_code_fastcall(PyThreadState *tstate, PyCodeObject *co, + PyObject *const *args, Py_ssize_t nargs, PyObject *globals) { - assert(globals != NULL); - - PyThreadState *tstate = _PyThreadState_GET(); assert(tstate != NULL); + assert(globals != NULL); /* XXX Perhaps we should create a specialized _PyFrame_New_NoTrack() that doesn't take locals, but does @@ -344,57 +343,61 @@ PyObject * _PyFunction_Vectorcall(PyObject *func, PyObject* const* stack, size_t nargsf, PyObject *kwnames) { + assert(PyFunction_Check(func)); + assert(kwnames == NULL || PyTuple_CheckExact(kwnames)); + + 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 *globals = PyFunction_GET_GLOBALS(func); PyObject *argdefs = PyFunction_GET_DEFAULTS(func); - PyObject *kwdefs, *closure, *name, *qualname; - PyObject **d; - Py_ssize_t nkwargs = (kwnames == NULL) ? 0 : PyTuple_GET_SIZE(kwnames); - Py_ssize_t nd; - - assert(PyFunction_Check(func)); - Py_ssize_t nargs = PyVectorcall_NARGS(nargsf); - assert(nargs >= 0); - assert(kwnames == NULL || PyTuple_CheckExact(kwnames)); - assert((nargs == 0 && nkwargs == 0) || stack != NULL); - /* kwnames must only contain strings and all keys must be unique */ 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(co, stack, nargs, globals); + return function_code_fastcall(tstate, co, stack, nargs, globals); } 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(co, stack, PyTuple_GET_SIZE(argdefs), + return function_code_fastcall(tstate, co, + stack, PyTuple_GET_SIZE(argdefs), globals); } } - kwdefs = PyFunction_GET_KW_DEFAULTS(func); - closure = PyFunction_GET_CLOSURE(func); - name = ((PyFunctionObject *)func) -> func_name; - qualname = ((PyFunctionObject *)func) -> func_qualname; + 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_EvalCodeWithName((PyObject*)co, globals, (PyObject *)NULL, - stack, nargs, - nkwargs ? _PyTuple_ITEMS(kwnames) : NULL, - stack + nargs, - nkwargs, 1, - d, (int)nd, kwdefs, - closure, name, qualname); + return _PyEval_EvalCode(tstate, + (PyObject*)co, globals, (PyObject *)NULL, + stack, nargs, + nkwargs ? _PyTuple_ITEMS(kwnames) : NULL, + stack + nargs, + nkwargs, 1, + d, (int)nd, kwdefs, + closure, name, qualname); } diff --git a/Python/ceval.c b/Python/ceval.c index 11d25a53d52..9f4b43615e2 100644 --- a/Python/ceval.c +++ b/Python/ceval.c @@ -4045,7 +4045,8 @@ fail: the test in the if statements in Misc/gdbinit (pystack and pystackv). */ PyObject * -_PyEval_EvalCodeWithName(PyObject *_co, PyObject *globals, PyObject *locals, +_PyEval_EvalCode(PyThreadState *tstate, + 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, @@ -4053,6 +4054,8 @@ _PyEval_EvalCodeWithName(PyObject *_co, PyObject *globals, PyObject *locals, PyObject *kwdefs, PyObject *closure, PyObject *name, PyObject *qualname) { + assert(tstate != NULL); + PyCodeObject* co = (PyCodeObject*)_co; PyFrameObject *f; PyObject *retval = NULL; @@ -4062,9 +4065,6 @@ _PyEval_EvalCodeWithName(PyObject *_co, PyObject *globals, PyObject *locals, Py_ssize_t i, j, n; PyObject *kwdict; - PyThreadState *tstate = _PyThreadState_GET(); - assert(tstate != NULL); - if (globals == NULL) { _PyErr_SetString(tstate, PyExc_SystemError, "PyEval_EvalCodeEx: NULL globals"); @@ -4319,6 +4319,26 @@ fail: /* Jump here from prelude on failure */ return retval; } + +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) +{ + PyThreadState *tstate = _PyThreadState_GET(); + return _PyEval_EvalCode(tstate, _co, globals, locals, + args, argcount, + kwnames, kwargs, + kwcount, kwstep, + defs, defcount, + kwdefs, closure, + name, qualname); +} + PyObject * PyEval_EvalCodeEx(PyObject *_co, PyObject *globals, PyObject *locals, PyObject *const *args, int argcount,