mirror of https://github.com/python/cpython
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
This commit is contained in:
parent
23a567c11c
commit
d6c33fbd34
|
@ -72,7 +72,7 @@ PyAPI_FUNC(PyFrameObject *) PyFrame_New(PyThreadState *, PyCodeObject *,
|
||||||
|
|
||||||
/* only internal use */
|
/* only internal use */
|
||||||
PyFrameObject* _PyFrame_New_NoTrack(PyThreadState *, PyCodeObject *,
|
PyFrameObject* _PyFrame_New_NoTrack(PyThreadState *, PyCodeObject *,
|
||||||
PyObject *, PyObject *);
|
PyObject *, PyObject *, PyObject *);
|
||||||
|
|
||||||
|
|
||||||
/* The rest of the interface is specific for frame objects */
|
/* 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(void) _PyFrame_DebugMallocStats(FILE *out);
|
||||||
|
|
||||||
PyAPI_FUNC(PyFrameObject *) PyFrame_GetBack(PyFrameObject *frame);
|
PyAPI_FUNC(PyFrameObject *) PyFrame_GetBack(PyFrameObject *frame);
|
||||||
|
|
||||||
|
PyObject *_PyEval_BuiltinsFromGlobals(PyObject *globals);
|
||||||
|
|
|
@ -7,6 +7,21 @@
|
||||||
extern "C" {
|
extern "C" {
|
||||||
#endif
|
#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 and code objects should not be confused with each other:
|
||||||
*
|
*
|
||||||
* Function objects are created by the execution of the 'def' statement.
|
* Function objects are created by the execution of the 'def' statement.
|
||||||
|
@ -20,18 +35,12 @@ extern "C" {
|
||||||
|
|
||||||
typedef struct {
|
typedef struct {
|
||||||
PyObject_HEAD
|
PyObject_HEAD
|
||||||
PyObject *func_code; /* A code object, the __code__ attribute */
|
COMMON_FIELDS(func_)
|
||||||
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 */
|
|
||||||
PyObject *func_doc; /* The __doc__ attribute, can be anything */
|
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_dict; /* The __dict__ attribute, a dict or NULL */
|
||||||
PyObject *func_weakreflist; /* List of weak references */
|
PyObject *func_weakreflist; /* List of weak references */
|
||||||
PyObject *func_module; /* The __module__ attribute, can be anything */
|
PyObject *func_module; /* The __module__ attribute, can be anything */
|
||||||
PyObject *func_annotations; /* Annotations, a dict or NULL */
|
PyObject *func_annotations; /* Annotations, a dict or NULL */
|
||||||
PyObject *func_qualname; /* The qualified name */
|
|
||||||
vectorcallfunc vectorcall;
|
vectorcallfunc vectorcall;
|
||||||
|
|
||||||
/* Invariant:
|
/* Invariant:
|
||||||
|
@ -84,6 +93,9 @@ PyAPI_FUNC(PyObject *) _PyFunction_Vectorcall(
|
||||||
#define PyFunction_GET_ANNOTATIONS(func) \
|
#define PyFunction_GET_ANNOTATIONS(func) \
|
||||||
(((PyFunctionObject *)func) -> func_annotations)
|
(((PyFunctionObject *)func) -> func_annotations)
|
||||||
|
|
||||||
|
#define PyFunction_AS_FRAME_CONSTRUCTOR(func) \
|
||||||
|
((PyFrameConstructor *)&((PyFunctionObject *)(func))->func_globals)
|
||||||
|
|
||||||
/* The classmethod and staticmethod types lives here, too */
|
/* The classmethod and staticmethod types lives here, too */
|
||||||
PyAPI_DATA(PyTypeObject) PyClassMethod_Type;
|
PyAPI_DATA(PyTypeObject) PyClassMethod_Type;
|
||||||
PyAPI_DATA(PyTypeObject) PyStaticMethod_Type;
|
PyAPI_DATA(PyTypeObject) PyStaticMethod_Type;
|
||||||
|
|
|
@ -42,13 +42,10 @@ _PyEval_EvalFrame(PyThreadState *tstate, PyFrameObject *f, int throwflag)
|
||||||
|
|
||||||
extern PyObject *_PyEval_EvalCode(
|
extern PyObject *_PyEval_EvalCode(
|
||||||
PyThreadState *tstate,
|
PyThreadState *tstate,
|
||||||
PyObject *_co, PyObject *globals, PyObject *locals,
|
PyFrameConstructor *desc, PyObject *locals,
|
||||||
PyObject *const *args, Py_ssize_t argcount,
|
PyObject *const *args, Py_ssize_t argcount,
|
||||||
PyObject *const *kwnames, PyObject *const *kwargs,
|
PyObject *const *kwnames, PyObject *const *kwargs,
|
||||||
Py_ssize_t kwcount, int kwstep,
|
Py_ssize_t kwcount, int kwstep);
|
||||||
PyObject *const *defs, Py_ssize_t defcount,
|
|
||||||
PyObject *kwdefs, PyObject *closure,
|
|
||||||
PyObject *name, PyObject *qualname);
|
|
||||||
|
|
||||||
#ifdef EXPERIMENTAL_ISOLATED_SUBINTERPRETERS
|
#ifdef EXPERIMENTAL_ISOLATED_SUBINTERPRETERS
|
||||||
extern int _PyEval_ThreadsInitialized(PyInterpreterState *interp);
|
extern int _PyEval_ThreadsInitialized(PyInterpreterState *interp);
|
||||||
|
|
|
@ -1280,7 +1280,7 @@ class SizeofTest(unittest.TestCase):
|
||||||
check(x, vsize('4Pi2c4P3ic' + CO_MAXBLOCKS*'3i' + 'P' + extras*'P'))
|
check(x, vsize('4Pi2c4P3ic' + CO_MAXBLOCKS*'3i' + 'P' + extras*'P'))
|
||||||
# function
|
# function
|
||||||
def func(): pass
|
def func(): pass
|
||||||
check(func, size('13P'))
|
check(func, size('14P'))
|
||||||
class c():
|
class c():
|
||||||
@staticmethod
|
@staticmethod
|
||||||
def foo():
|
def foo():
|
||||||
|
|
|
@ -331,16 +331,16 @@ PyCFunction_Call(PyObject *callable, PyObject *args, PyObject *kwargs)
|
||||||
static PyObject* _Py_HOT_FUNCTION
|
static PyObject* _Py_HOT_FUNCTION
|
||||||
function_code_fastcall(PyThreadState *tstate, PyCodeObject *co,
|
function_code_fastcall(PyThreadState *tstate, PyCodeObject *co,
|
||||||
PyObject *const *args, Py_ssize_t nargs,
|
PyObject *const *args, Py_ssize_t nargs,
|
||||||
PyObject *globals)
|
PyFunctionObject *func)
|
||||||
{
|
{
|
||||||
assert(tstate != NULL);
|
assert(tstate != NULL);
|
||||||
assert(globals != NULL);
|
assert(func != NULL);
|
||||||
|
|
||||||
/* XXX Perhaps we should create a specialized
|
/* XXX Perhaps we should create a specialized
|
||||||
_PyFrame_New_NoTrack() that doesn't take locals, but does
|
_PyFrame_New_NoTrack() that doesn't take locals, but does
|
||||||
take builtins without sanity checking them.
|
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) {
|
if (f == NULL) {
|
||||||
return NULL;
|
return NULL;
|
||||||
}
|
}
|
||||||
|
@ -381,14 +381,13 @@ _PyFunction_Vectorcall(PyObject *func, PyObject* const* stack,
|
||||||
|
|
||||||
PyThreadState *tstate = _PyThreadState_GET();
|
PyThreadState *tstate = _PyThreadState_GET();
|
||||||
PyCodeObject *co = (PyCodeObject *)PyFunction_GET_CODE(func);
|
PyCodeObject *co = (PyCodeObject *)PyFunction_GET_CODE(func);
|
||||||
PyObject *globals = PyFunction_GET_GLOBALS(func);
|
|
||||||
PyObject *argdefs = PyFunction_GET_DEFAULTS(func);
|
PyObject *argdefs = PyFunction_GET_DEFAULTS(func);
|
||||||
|
|
||||||
if (co->co_kwonlyargcount == 0 && nkwargs == 0 &&
|
if (co->co_kwonlyargcount == 0 && nkwargs == 0 &&
|
||||||
(co->co_flags & ~PyCF_MASK) == (CO_OPTIMIZED | CO_NEWLOCALS | CO_NOFREE))
|
(co->co_flags & ~PyCF_MASK) == (CO_OPTIMIZED | CO_NEWLOCALS | CO_NOFREE))
|
||||||
{
|
{
|
||||||
if (argdefs == NULL && co->co_argcount == nargs) {
|
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
|
else if (nargs == 0 && argdefs != NULL
|
||||||
&& co->co_argcount == PyTuple_GET_SIZE(argdefs)) {
|
&& co->co_argcount == PyTuple_GET_SIZE(argdefs)) {
|
||||||
|
@ -397,34 +396,16 @@ _PyFunction_Vectorcall(PyObject *func, PyObject* const* stack,
|
||||||
stack = _PyTuple_ITEMS(argdefs);
|
stack = _PyTuple_ITEMS(argdefs);
|
||||||
return function_code_fastcall(tstate, co,
|
return function_code_fastcall(tstate, co,
|
||||||
stack, PyTuple_GET_SIZE(argdefs),
|
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,
|
return _PyEval_EvalCode(tstate,
|
||||||
(PyObject*)co, globals, (PyObject *)NULL,
|
PyFunction_AS_FRAME_CONSTRUCTOR(func), (PyObject *)NULL,
|
||||||
stack, nargs,
|
stack, nargs,
|
||||||
nkwargs ? _PyTuple_ITEMS(kwnames) : NULL,
|
nkwargs ? _PyTuple_ITEMS(kwnames) : NULL,
|
||||||
stack + nargs,
|
stack + nargs,
|
||||||
nkwargs, 1,
|
nkwargs, 1);
|
||||||
d, (int)nd, kwdefs,
|
|
||||||
closure, name, qualname);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
|
@ -22,7 +22,6 @@ static PyMemberDef frame_memberlist[] = {
|
||||||
{NULL} /* Sentinel */
|
{NULL} /* Sentinel */
|
||||||
};
|
};
|
||||||
|
|
||||||
|
|
||||||
static struct _Py_frame_state *
|
static struct _Py_frame_state *
|
||||||
get_frame_state(void)
|
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
|
PyFrameObject* _Py_HOT_FUNCTION
|
||||||
_PyFrame_New_NoTrack(PyThreadState *tstate, PyCodeObject *code,
|
_PyFrame_New_NoTrack(PyThreadState *tstate, PyCodeObject *code,
|
||||||
PyObject *globals, PyObject *locals)
|
PyObject *globals, PyObject *builtins, PyObject *locals)
|
||||||
{
|
{
|
||||||
#ifdef Py_DEBUG
|
#ifdef Py_DEBUG
|
||||||
if (code == NULL || globals == NULL || !PyDict_Check(globals) ||
|
if (code == NULL || globals == NULL || builtins == NULL ||
|
||||||
(locals != NULL && !PyMapping_Check(locals))) {
|
(locals != NULL && !PyMapping_Check(locals))) {
|
||||||
PyErr_BadInternalCall();
|
PyErr_BadInternalCall();
|
||||||
return NULL;
|
return NULL;
|
||||||
|
@ -871,18 +828,14 @@ _PyFrame_New_NoTrack(PyThreadState *tstate, PyCodeObject *code,
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
PyFrameObject *back = tstate->frame;
|
PyFrameObject *back = tstate->frame;
|
||||||
PyObject *builtins = frame_get_builtins(back, globals);
|
|
||||||
if (builtins == NULL) {
|
|
||||||
return NULL;
|
|
||||||
}
|
|
||||||
|
|
||||||
PyFrameObject *f = frame_alloc(code);
|
PyFrameObject *f = frame_alloc(code);
|
||||||
if (f == NULL) {
|
if (f == NULL) {
|
||||||
Py_DECREF(builtins);
|
|
||||||
return NULL;
|
return NULL;
|
||||||
}
|
}
|
||||||
|
|
||||||
f->f_stackdepth = 0;
|
f->f_stackdepth = 0;
|
||||||
|
Py_INCREF(builtins);
|
||||||
f->f_builtins = builtins;
|
f->f_builtins = builtins;
|
||||||
Py_XINCREF(back);
|
Py_XINCREF(back);
|
||||||
f->f_back = back;
|
f->f_back = back;
|
||||||
|
@ -902,8 +855,9 @@ _PyFrame_New_NoTrack(PyThreadState *tstate, PyCodeObject *code,
|
||||||
f->f_locals = locals;
|
f->f_locals = locals;
|
||||||
}
|
}
|
||||||
else {
|
else {
|
||||||
if (locals == NULL)
|
if (locals == NULL) {
|
||||||
locals = globals;
|
locals = globals;
|
||||||
|
}
|
||||||
Py_INCREF(locals);
|
Py_INCREF(locals);
|
||||||
f->f_locals = locals;
|
f->f_locals = locals;
|
||||||
}
|
}
|
||||||
|
@ -925,7 +879,9 @@ PyFrameObject*
|
||||||
PyFrame_New(PyThreadState *tstate, PyCodeObject *code,
|
PyFrame_New(PyThreadState *tstate, PyCodeObject *code,
|
||||||
PyObject *globals, PyObject *locals)
|
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)
|
if (f)
|
||||||
_PyObject_GC_TRACK(f);
|
_PyObject_GC_TRACK(f);
|
||||||
return f;
|
return f;
|
||||||
|
@ -1223,3 +1179,28 @@ PyFrame_GetBack(PyFrameObject *frame)
|
||||||
Py_XINCREF(back);
|
Py_XINCREF(back);
|
||||||
return 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;
|
||||||
|
}
|
||||||
|
|
|
@ -3,6 +3,7 @@
|
||||||
|
|
||||||
#include "Python.h"
|
#include "Python.h"
|
||||||
#include "pycore_object.h"
|
#include "pycore_object.h"
|
||||||
|
#include "frameobject.h"
|
||||||
#include "code.h"
|
#include "code.h"
|
||||||
#include "structmember.h" // PyMemberDef
|
#include "structmember.h" // PyMemberDef
|
||||||
|
|
||||||
|
@ -40,8 +41,14 @@ PyFunction_NewWithQualName(PyObject *code, PyObject *globals, PyObject *qualname
|
||||||
op->func_weakreflist = NULL;
|
op->func_weakreflist = NULL;
|
||||||
Py_INCREF(code);
|
Py_INCREF(code);
|
||||||
op->func_code = code;
|
op->func_code = code;
|
||||||
|
assert(globals != NULL);
|
||||||
Py_INCREF(globals);
|
Py_INCREF(globals);
|
||||||
op->func_globals = 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;
|
op->func_name = ((PyCodeObject *)code)->co_name;
|
||||||
Py_INCREF(op->func_name);
|
Py_INCREF(op->func_name);
|
||||||
op->func_defaults = NULL; /* No default arguments */
|
op->func_defaults = NULL; /* No default arguments */
|
||||||
|
@ -592,15 +599,16 @@ func_clear(PyFunctionObject *op)
|
||||||
{
|
{
|
||||||
Py_CLEAR(op->func_code);
|
Py_CLEAR(op->func_code);
|
||||||
Py_CLEAR(op->func_globals);
|
Py_CLEAR(op->func_globals);
|
||||||
Py_CLEAR(op->func_module);
|
Py_CLEAR(op->func_builtins);
|
||||||
Py_CLEAR(op->func_name);
|
Py_CLEAR(op->func_name);
|
||||||
|
Py_CLEAR(op->func_qualname);
|
||||||
|
Py_CLEAR(op->func_module);
|
||||||
Py_CLEAR(op->func_defaults);
|
Py_CLEAR(op->func_defaults);
|
||||||
Py_CLEAR(op->func_kwdefaults);
|
Py_CLEAR(op->func_kwdefaults);
|
||||||
Py_CLEAR(op->func_doc);
|
Py_CLEAR(op->func_doc);
|
||||||
Py_CLEAR(op->func_dict);
|
Py_CLEAR(op->func_dict);
|
||||||
Py_CLEAR(op->func_closure);
|
Py_CLEAR(op->func_closure);
|
||||||
Py_CLEAR(op->func_annotations);
|
Py_CLEAR(op->func_annotations);
|
||||||
Py_CLEAR(op->func_qualname);
|
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -627,6 +635,7 @@ func_traverse(PyFunctionObject *f, visitproc visit, void *arg)
|
||||||
{
|
{
|
||||||
Py_VISIT(f->func_code);
|
Py_VISIT(f->func_code);
|
||||||
Py_VISIT(f->func_globals);
|
Py_VISIT(f->func_globals);
|
||||||
|
Py_VISIT(f->func_builtins);
|
||||||
Py_VISIT(f->func_module);
|
Py_VISIT(f->func_module);
|
||||||
Py_VISIT(f->func_defaults);
|
Py_VISIT(f->func_defaults);
|
||||||
Py_VISIT(f->func_kwdefaults);
|
Py_VISIT(f->func_kwdefaults);
|
||||||
|
|
130
Python/ceval.c
130
Python/ceval.c
|
@ -3888,7 +3888,7 @@ main_loop:
|
||||||
|
|
||||||
if (oparg & 0x08) {
|
if (oparg & 0x08) {
|
||||||
assert(PyTuple_CheckExact(TOP()));
|
assert(PyTuple_CheckExact(TOP()));
|
||||||
func ->func_closure = POP();
|
func->func_closure = POP();
|
||||||
}
|
}
|
||||||
if (oparg & 0x04) {
|
if (oparg & 0x04) {
|
||||||
assert(PyTuple_CheckExact(TOP()));
|
assert(PyTuple_CheckExact(TOP()));
|
||||||
|
@ -4233,7 +4233,7 @@ missing_arguments(PyThreadState *tstate, PyCodeObject *co,
|
||||||
|
|
||||||
static void
|
static void
|
||||||
too_many_positional(PyThreadState *tstate, PyCodeObject *co,
|
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)
|
PyObject **fastlocals, PyObject *qualname)
|
||||||
{
|
{
|
||||||
int plural;
|
int plural;
|
||||||
|
@ -4249,6 +4249,7 @@ too_many_positional(PyThreadState *tstate, PyCodeObject *co,
|
||||||
kwonly_given++;
|
kwonly_given++;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
Py_ssize_t defcount = defaults == NULL ? 0 : PyTuple_GET_SIZE(defaults);
|
||||||
if (defcount) {
|
if (defcount) {
|
||||||
Py_ssize_t atleast = co_argcount - defcount;
|
Py_ssize_t atleast = co_argcount - defcount;
|
||||||
plural = 1;
|
plural = 1;
|
||||||
|
@ -4356,41 +4357,20 @@ fail:
|
||||||
|
|
||||||
PyObject *
|
PyObject *
|
||||||
_PyEval_EvalCode(PyThreadState *tstate,
|
_PyEval_EvalCode(PyThreadState *tstate,
|
||||||
PyObject *_co, PyObject *globals, 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 *const *kwnames, PyObject *const *kwargs,
|
||||||
Py_ssize_t kwcount, int kwstep,
|
Py_ssize_t kwcount, int kwstep)
|
||||||
PyObject *const *defs, Py_ssize_t defcount,
|
|
||||||
PyObject *kwdefs, PyObject *closure,
|
|
||||||
PyObject *name, PyObject *qualname)
|
|
||||||
{
|
{
|
||||||
assert(is_tstate_valid(tstate));
|
assert(is_tstate_valid(tstate));
|
||||||
|
|
||||||
PyCodeObject *co = (PyCodeObject*)_co;
|
PyCodeObject *co = (PyCodeObject*)con->fc_code;
|
||||||
|
assert(con->fc_defaults == NULL || PyTuple_CheckExact(con->fc_defaults));
|
||||||
if (!name) {
|
|
||||||
name = co->co_name;
|
|
||||||
}
|
|
||||||
assert(name != NULL);
|
|
||||||
assert(PyUnicode_Check(name));
|
|
||||||
|
|
||||||
if (!qualname) {
|
|
||||||
qualname = name;
|
|
||||||
}
|
|
||||||
assert(qualname != NULL);
|
|
||||||
assert(PyUnicode_Check(qualname));
|
|
||||||
|
|
||||||
PyObject *retval = NULL;
|
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;
|
||||||
|
|
||||||
if (globals == NULL) {
|
|
||||||
_PyErr_SetString(tstate, PyExc_SystemError,
|
|
||||||
"PyEval_EvalCodeEx: NULL globals");
|
|
||||||
return NULL;
|
|
||||||
}
|
|
||||||
|
|
||||||
/* Create the frame */
|
/* 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) {
|
if (f == NULL) {
|
||||||
return NULL;
|
return NULL;
|
||||||
}
|
}
|
||||||
|
@ -4448,7 +4428,7 @@ _PyEval_EvalCode(PyThreadState *tstate,
|
||||||
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",
|
||||||
qualname);
|
con->fc_qualname);
|
||||||
goto fail;
|
goto fail;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -4480,14 +4460,14 @@ _PyEval_EvalCode(PyThreadState *tstate,
|
||||||
if (co->co_posonlyargcount
|
if (co->co_posonlyargcount
|
||||||
&& positional_only_passed_as_keyword(tstate, co,
|
&& positional_only_passed_as_keyword(tstate, co,
|
||||||
kwcount, kwnames,
|
kwcount, kwnames,
|
||||||
qualname))
|
con->fc_qualname))
|
||||||
{
|
{
|
||||||
goto fail;
|
goto fail;
|
||||||
}
|
}
|
||||||
|
|
||||||
_PyErr_Format(tstate, PyExc_TypeError,
|
_PyErr_Format(tstate, PyExc_TypeError,
|
||||||
"%U() got an unexpected keyword argument '%S'",
|
"%U() got an unexpected keyword argument '%S'",
|
||||||
qualname, keyword);
|
con->fc_qualname, keyword);
|
||||||
goto fail;
|
goto fail;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -4500,7 +4480,7 @@ _PyEval_EvalCode(PyThreadState *tstate,
|
||||||
if (GETLOCAL(j) != NULL) {
|
if (GETLOCAL(j) != NULL) {
|
||||||
_PyErr_Format(tstate, PyExc_TypeError,
|
_PyErr_Format(tstate, PyExc_TypeError,
|
||||||
"%U() got multiple values for argument '%S'",
|
"%U() got multiple values for argument '%S'",
|
||||||
qualname, keyword);
|
con->fc_qualname, keyword);
|
||||||
goto fail;
|
goto fail;
|
||||||
}
|
}
|
||||||
Py_INCREF(value);
|
Py_INCREF(value);
|
||||||
|
@ -4509,13 +4489,14 @@ _PyEval_EvalCode(PyThreadState *tstate,
|
||||||
|
|
||||||
/* Check the number of positional arguments */
|
/* Check the number of positional arguments */
|
||||||
if ((argcount > co->co_argcount) && !(co->co_flags & CO_VARARGS)) {
|
if ((argcount > co->co_argcount) && !(co->co_flags & CO_VARARGS)) {
|
||||||
too_many_positional(tstate, co, argcount, defcount, fastlocals,
|
too_many_positional(tstate, co, argcount, con->fc_defaults, fastlocals,
|
||||||
qualname);
|
con->fc_qualname);
|
||||||
goto fail;
|
goto fail;
|
||||||
}
|
}
|
||||||
|
|
||||||
/* Add missing positional arguments (copy default values from defs) */
|
/* Add missing positional arguments (copy default values from defs) */
|
||||||
if (argcount < co->co_argcount) {
|
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 m = co->co_argcount - defcount;
|
||||||
Py_ssize_t missing = 0;
|
Py_ssize_t missing = 0;
|
||||||
for (i = argcount; i < m; i++) {
|
for (i = argcount; i < m; i++) {
|
||||||
|
@ -4525,18 +4506,21 @@ _PyEval_EvalCode(PyThreadState *tstate,
|
||||||
}
|
}
|
||||||
if (missing) {
|
if (missing) {
|
||||||
missing_arguments(tstate, co, missing, defcount, fastlocals,
|
missing_arguments(tstate, co, missing, defcount, fastlocals,
|
||||||
qualname);
|
con->fc_qualname);
|
||||||
goto fail;
|
goto fail;
|
||||||
}
|
}
|
||||||
if (n > m)
|
if (n > m)
|
||||||
i = n - m;
|
i = n - m;
|
||||||
else
|
else
|
||||||
i = 0;
|
i = 0;
|
||||||
for (; i < defcount; i++) {
|
if (defcount) {
|
||||||
if (GETLOCAL(m+i) == NULL) {
|
PyObject **defs = &PyTuple_GET_ITEM(con->fc_defaults, 0);
|
||||||
PyObject *def = defs[i];
|
for (; i < defcount; i++) {
|
||||||
Py_INCREF(def);
|
if (GETLOCAL(m+i) == NULL) {
|
||||||
SETLOCAL(m+i, def);
|
PyObject *def = defs[i];
|
||||||
|
Py_INCREF(def);
|
||||||
|
SETLOCAL(m+i, def);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -4548,8 +4532,8 @@ _PyEval_EvalCode(PyThreadState *tstate,
|
||||||
if (GETLOCAL(i) != NULL)
|
if (GETLOCAL(i) != NULL)
|
||||||
continue;
|
continue;
|
||||||
PyObject *varname = PyTuple_GET_ITEM(co->co_varnames, i);
|
PyObject *varname = PyTuple_GET_ITEM(co->co_varnames, i);
|
||||||
if (kwdefs != NULL) {
|
if (con->fc_kwdefaults != NULL) {
|
||||||
PyObject *def = PyDict_GetItemWithError(kwdefs, varname);
|
PyObject *def = PyDict_GetItemWithError(con->fc_kwdefaults, varname);
|
||||||
if (def) {
|
if (def) {
|
||||||
Py_INCREF(def);
|
Py_INCREF(def);
|
||||||
SETLOCAL(i, def);
|
SETLOCAL(i, def);
|
||||||
|
@ -4563,7 +4547,7 @@ _PyEval_EvalCode(PyThreadState *tstate,
|
||||||
}
|
}
|
||||||
if (missing) {
|
if (missing) {
|
||||||
missing_arguments(tstate, co, missing, -1, fastlocals,
|
missing_arguments(tstate, co, missing, -1, fastlocals,
|
||||||
qualname);
|
con->fc_qualname);
|
||||||
goto fail;
|
goto fail;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -4590,7 +4574,7 @@ _PyEval_EvalCode(PyThreadState *tstate,
|
||||||
|
|
||||||
/* Copy closure variables to free variables */
|
/* Copy closure variables to free variables */
|
||||||
for (i = 0; i < PyTuple_GET_SIZE(co->co_freevars); ++i) {
|
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);
|
Py_INCREF(o);
|
||||||
freevars[PyTuple_GET_SIZE(co->co_cellvars) + i] = 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
|
/* Create a new generator that owns the ready to run frame
|
||||||
* and return that as the value. */
|
* and return that as the value. */
|
||||||
if (is_coro) {
|
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) {
|
} 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 {
|
} else {
|
||||||
gen = PyGen_NewWithQualName(f, name, qualname);
|
gen = PyGen_NewWithQualName(f, con->fc_name, con->fc_qualname);
|
||||||
}
|
}
|
||||||
if (gen == NULL) {
|
if (gen == NULL) {
|
||||||
return NULL;
|
return NULL;
|
||||||
|
@ -4643,7 +4627,7 @@ fail: /* Jump here from prelude on failure */
|
||||||
return retval;
|
return retval;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/* Legacy API */
|
||||||
PyObject *
|
PyObject *
|
||||||
_PyEval_EvalCodeWithName(PyObject *_co, PyObject *globals, PyObject *locals,
|
_PyEval_EvalCodeWithName(PyObject *_co, PyObject *globals, PyObject *locals,
|
||||||
PyObject *const *args, Py_ssize_t argcount,
|
PyObject *const *args, Py_ssize_t argcount,
|
||||||
|
@ -4653,16 +4637,36 @@ _PyEval_EvalCodeWithName(PyObject *_co, PyObject *globals, PyObject *locals,
|
||||||
PyObject *kwdefs, PyObject *closure,
|
PyObject *kwdefs, PyObject *closure,
|
||||||
PyObject *name, PyObject *qualname)
|
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();
|
PyThreadState *tstate = _PyThreadState_GET();
|
||||||
return _PyEval_EvalCode(tstate, _co, globals, locals,
|
PyObject *res = _PyEval_EvalCode(tstate, &constr, locals,
|
||||||
args, argcount,
|
args, argcount,
|
||||||
kwnames, kwargs,
|
kwnames, kwargs,
|
||||||
kwcount, kwstep,
|
kwcount, kwstep);
|
||||||
defs, defcount,
|
Py_DECREF(defaults);
|
||||||
kwdefs, closure,
|
Py_DECREF(builtins);
|
||||||
name, qualname);
|
return res;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/* Legacy API */
|
||||||
PyObject *
|
PyObject *
|
||||||
PyEval_EvalCodeEx(PyObject *_co, PyObject *globals, PyObject *locals,
|
PyEval_EvalCodeEx(PyObject *_co, PyObject *globals, PyObject *locals,
|
||||||
PyObject *const *args, int argcount,
|
PyObject *const *args, int argcount,
|
||||||
|
@ -4670,13 +4674,15 @@ PyEval_EvalCodeEx(PyObject *_co, PyObject *globals, PyObject *locals,
|
||||||
PyObject *const *defs, int defcount,
|
PyObject *const *defs, int defcount,
|
||||||
PyObject *kwdefs, PyObject *closure)
|
PyObject *kwdefs, PyObject *closure)
|
||||||
{
|
{
|
||||||
return _PyEval_EvalCodeWithName(_co, globals, locals,
|
return _PyEval_EvalCodeWithName(
|
||||||
args, argcount,
|
_co, globals, locals,
|
||||||
kws, kws != NULL ? kws + 1 : NULL,
|
args, argcount,
|
||||||
kwcount, 2,
|
kws, kws != NULL ? kws + 1 : NULL,
|
||||||
defs, defcount,
|
kwcount, 2,
|
||||||
kwdefs, closure,
|
defs, defcount,
|
||||||
NULL, NULL);
|
kwdefs, closure,
|
||||||
|
((PyCodeObject *)_co)->co_name,
|
||||||
|
((PyCodeObject *)_co)->co_name);
|
||||||
}
|
}
|
||||||
|
|
||||||
static PyObject *
|
static PyObject *
|
||||||
|
|
Loading…
Reference in New Issue