diff options
author | Mark Shannon <mark@hotpy.org> | 2021-05-21 09:57:35 (GMT) |
---|---|---|
committer | GitHub <noreply@github.com> | 2021-05-21 09:57:35 (GMT) |
commit | b11a951f16f0603d98de24fee5c023df83ea552c (patch) | |
tree | 82e7807515db0e284d9ebc3b8c3ba6ff08699ea5 /Python/ceval.c | |
parent | be4dd7fcd93ed29d362c4bbcc48151bc619d6595 (diff) | |
download | cpython-b11a951f16f0603d98de24fee5c023df83ea552c.zip cpython-b11a951f16f0603d98de24fee5c023df83ea552c.tar.gz cpython-b11a951f16f0603d98de24fee5c023df83ea552c.tar.bz2 |
bpo-44032: Move data stack to thread from FrameObject. (GH-26076)
* Remove 'zombie' frames. We won't need them once we are allocating fixed-size frames.
* Add co_nlocalplus field to code object to avoid recomputing size of locals + frees + cells.
* Move locals, cells and freevars out of frame object into separate memory buffer.
* Use per-threadstate allocated memory chunks for local variables.
* Move globals and builtins from frame object to per-thread stack.
* Move (slow) locals frame object to per-thread stack.
* Move internal frame functions to internal header.
Diffstat (limited to 'Python/ceval.c')
-rw-r--r-- | Python/ceval.c | 195 |
1 files changed, 114 insertions, 81 deletions
diff --git a/Python/ceval.c b/Python/ceval.c index 744e2fe..e4a6a65 100644 --- a/Python/ceval.c +++ b/Python/ceval.c @@ -26,6 +26,7 @@ #include "code.h" #include "dictobject.h" #include "frameobject.h" +#include "pycore_frame.h" #include "opcode.h" #include "pydtrace.h" #include "setobject.h" @@ -1547,6 +1548,9 @@ eval_frame_handle_pending(PyThreadState *tstate) #endif +#define GLOBALS() specials[FRAME_SPECIALS_GLOBALS_OFFSET] +#define BUILTINS() specials[FRAME_SPECIALS_BUILTINS_OFFSET] +#define LOCALS() specials[FRAME_SPECIALS_LOCALS_OFFSET] PyObject* _Py_HOT_FUNCTION _PyEval_EvalFrameDefault(PyThreadState *tstate, PyFrameObject *f, int throwflag) @@ -1565,7 +1569,7 @@ _PyEval_EvalFrameDefault(PyThreadState *tstate, PyFrameObject *f, int throwflag) const _Py_CODEUNIT *next_instr; int opcode; /* Current opcode */ int oparg; /* Current opcode argument, if any */ - PyObject **fastlocals, **freevars; + PyObject **fastlocals, **freevars, **specials; PyObject *retval = NULL; /* Return value */ _Py_atomic_int * const eval_breaker = &tstate->interp->ceval.eval_breaker; PyCodeObject *co; @@ -1598,6 +1602,7 @@ _PyEval_EvalFrameDefault(PyThreadState *tstate, PyFrameObject *f, int throwflag) /* push frame */ tstate->frame = f; + specials = f->f_valuestack - FRAME_SPECIALS_SIZE; co = f->f_code; if (trace_info.cframe.use_tracing) { @@ -1641,8 +1646,8 @@ _PyEval_EvalFrameDefault(PyThreadState *tstate, PyFrameObject *f, int throwflag) names = co->co_names; consts = co->co_consts; - fastlocals = f->f_localsplus; - freevars = f->f_localsplus + co->co_nlocals; + fastlocals = f->f_localsptr; + freevars = f->f_localsptr + co->co_nlocals; assert(PyBytes_Check(co->co_code)); assert(PyBytes_GET_SIZE(co->co_code) <= INT_MAX); assert(PyBytes_GET_SIZE(co->co_code) % sizeof(_Py_CODEUNIT) == 0); @@ -1692,7 +1697,7 @@ _PyEval_EvalFrameDefault(PyThreadState *tstate, PyFrameObject *f, int throwflag) #ifdef LLTRACE { - int r = _PyDict_ContainsId(f->f_globals, &PyId___ltrace__); + int r = _PyDict_ContainsId(GLOBALS(), &PyId___ltrace__); if (r < 0) { goto exit_eval_frame; } @@ -2726,8 +2731,8 @@ _PyEval_EvalFrameDefault(PyThreadState *tstate, PyFrameObject *f, int throwflag) _Py_IDENTIFIER(__build_class__); PyObject *bc; - if (PyDict_CheckExact(f->f_builtins)) { - bc = _PyDict_GetItemIdWithError(f->f_builtins, &PyId___build_class__); + if (PyDict_CheckExact(BUILTINS())) { + bc = _PyDict_GetItemIdWithError(BUILTINS(), &PyId___build_class__); if (bc == NULL) { if (!_PyErr_Occurred(tstate)) { _PyErr_SetString(tstate, PyExc_NameError, @@ -2741,7 +2746,7 @@ _PyEval_EvalFrameDefault(PyThreadState *tstate, PyFrameObject *f, int throwflag) PyObject *build_class_str = _PyUnicode_FromId(&PyId___build_class__); if (build_class_str == NULL) goto error; - bc = PyObject_GetItem(f->f_builtins, build_class_str); + bc = PyObject_GetItem(BUILTINS(), build_class_str); if (bc == NULL) { if (_PyErr_ExceptionMatches(tstate, PyExc_KeyError)) _PyErr_SetString(tstate, PyExc_NameError, @@ -2756,7 +2761,7 @@ _PyEval_EvalFrameDefault(PyThreadState *tstate, PyFrameObject *f, int throwflag) case TARGET(STORE_NAME): { PyObject *name = GETITEM(names, oparg); PyObject *v = POP(); - PyObject *ns = f->f_locals; + PyObject *ns = LOCALS(); int err; if (ns == NULL) { _PyErr_Format(tstate, PyExc_SystemError, @@ -2776,7 +2781,7 @@ _PyEval_EvalFrameDefault(PyThreadState *tstate, PyFrameObject *f, int throwflag) case TARGET(DELETE_NAME): { PyObject *name = GETITEM(names, oparg); - PyObject *ns = f->f_locals; + PyObject *ns = LOCALS(); int err; if (ns == NULL) { _PyErr_Format(tstate, PyExc_SystemError, @@ -2868,7 +2873,7 @@ _PyEval_EvalFrameDefault(PyThreadState *tstate, PyFrameObject *f, int throwflag) PyObject *name = GETITEM(names, oparg); PyObject *v = POP(); int err; - err = PyDict_SetItem(f->f_globals, name, v); + err = PyDict_SetItem(GLOBALS(), name, v); Py_DECREF(v); if (err != 0) goto error; @@ -2878,7 +2883,7 @@ _PyEval_EvalFrameDefault(PyThreadState *tstate, PyFrameObject *f, int throwflag) case TARGET(DELETE_GLOBAL): { PyObject *name = GETITEM(names, oparg); int err; - err = PyDict_DelItem(f->f_globals, name); + err = PyDict_DelItem(GLOBALS(), name); if (err != 0) { if (_PyErr_ExceptionMatches(tstate, PyExc_KeyError)) { format_exc_check_arg(tstate, PyExc_NameError, @@ -2891,7 +2896,7 @@ _PyEval_EvalFrameDefault(PyThreadState *tstate, PyFrameObject *f, int throwflag) case TARGET(LOAD_NAME): { PyObject *name = GETITEM(names, oparg); - PyObject *locals = f->f_locals; + PyObject *locals = LOCALS(); PyObject *v; if (locals == NULL) { _PyErr_Format(tstate, PyExc_SystemError, @@ -2916,7 +2921,7 @@ _PyEval_EvalFrameDefault(PyThreadState *tstate, PyFrameObject *f, int throwflag) } } if (v == NULL) { - v = PyDict_GetItemWithError(f->f_globals, name); + v = PyDict_GetItemWithError(GLOBALS(), name); if (v != NULL) { Py_INCREF(v); } @@ -2924,8 +2929,8 @@ _PyEval_EvalFrameDefault(PyThreadState *tstate, PyFrameObject *f, int throwflag) goto error; } else { - if (PyDict_CheckExact(f->f_builtins)) { - v = PyDict_GetItemWithError(f->f_builtins, name); + if (PyDict_CheckExact(BUILTINS())) { + v = PyDict_GetItemWithError(BUILTINS(), name); if (v == NULL) { if (!_PyErr_Occurred(tstate)) { format_exc_check_arg( @@ -2937,7 +2942,7 @@ _PyEval_EvalFrameDefault(PyThreadState *tstate, PyFrameObject *f, int throwflag) Py_INCREF(v); } else { - v = PyObject_GetItem(f->f_builtins, name); + v = PyObject_GetItem(BUILTINS(), name); if (v == NULL) { if (_PyErr_ExceptionMatches(tstate, PyExc_KeyError)) { format_exc_check_arg( @@ -2956,17 +2961,17 @@ _PyEval_EvalFrameDefault(PyThreadState *tstate, PyFrameObject *f, int throwflag) case TARGET(LOAD_GLOBAL): { PyObject *name; PyObject *v; - if (PyDict_CheckExact(f->f_globals) - && PyDict_CheckExact(f->f_builtins)) + if (PyDict_CheckExact(GLOBALS()) + && PyDict_CheckExact(BUILTINS())) { OPCACHE_CHECK(); if (co_opcache != NULL && co_opcache->optimized > 0) { _PyOpcache_LoadGlobal *lg = &co_opcache->u.lg; if (lg->globals_ver == - ((PyDictObject *)f->f_globals)->ma_version_tag + ((PyDictObject *)GLOBALS())->ma_version_tag && lg->builtins_ver == - ((PyDictObject *)f->f_builtins)->ma_version_tag) + ((PyDictObject *)BUILTINS())->ma_version_tag) { PyObject *ptr = lg->ptr; OPCACHE_STAT_GLOBAL_HIT(); @@ -2978,8 +2983,8 @@ _PyEval_EvalFrameDefault(PyThreadState *tstate, PyFrameObject *f, int throwflag) } name = GETITEM(names, oparg); - v = _PyDict_LoadGlobal((PyDictObject *)f->f_globals, - (PyDictObject *)f->f_builtins, + v = _PyDict_LoadGlobal((PyDictObject *)GLOBALS(), + (PyDictObject *)BUILTINS(), name); if (v == NULL) { if (!_PyErr_Occurred(tstate)) { @@ -3003,9 +3008,9 @@ _PyEval_EvalFrameDefault(PyThreadState *tstate, PyFrameObject *f, int throwflag) co_opcache->optimized = 1; lg->globals_ver = - ((PyDictObject *)f->f_globals)->ma_version_tag; + ((PyDictObject *)GLOBALS())->ma_version_tag; lg->builtins_ver = - ((PyDictObject *)f->f_builtins)->ma_version_tag; + ((PyDictObject *)BUILTINS())->ma_version_tag; lg->ptr = v; /* borrowed */ } @@ -3016,7 +3021,7 @@ _PyEval_EvalFrameDefault(PyThreadState *tstate, PyFrameObject *f, int throwflag) /* namespace 1: globals */ name = GETITEM(names, oparg); - v = PyObject_GetItem(f->f_globals, name); + v = PyObject_GetItem(GLOBALS(), name); if (v == NULL) { if (!_PyErr_ExceptionMatches(tstate, PyExc_KeyError)) { goto error; @@ -3024,7 +3029,7 @@ _PyEval_EvalFrameDefault(PyThreadState *tstate, PyFrameObject *f, int throwflag) _PyErr_Clear(tstate); /* namespace 2: builtins */ - v = PyObject_GetItem(f->f_builtins, name); + v = PyObject_GetItem(BUILTINS(), name); if (v == NULL) { if (_PyErr_ExceptionMatches(tstate, PyExc_KeyError)) { format_exc_check_arg( @@ -3073,7 +3078,7 @@ _PyEval_EvalFrameDefault(PyThreadState *tstate, PyFrameObject *f, int throwflag) } case TARGET(LOAD_CLASSDEREF): { - PyObject *name, *value, *locals = f->f_locals; + PyObject *name, *value, *locals = LOCALS(); Py_ssize_t idx; assert(locals); assert(oparg >= PyTuple_GET_SIZE(co->co_cellvars)); @@ -3266,14 +3271,14 @@ _PyEval_EvalFrameDefault(PyThreadState *tstate, PyFrameObject *f, int throwflag) _Py_IDENTIFIER(__annotations__); int err; PyObject *ann_dict; - if (f->f_locals == NULL) { + if (LOCALS() == NULL) { _PyErr_Format(tstate, PyExc_SystemError, "no locals found when setting up annotations"); goto error; } /* check if __annotations__ in locals()... */ - if (PyDict_CheckExact(f->f_locals)) { - ann_dict = _PyDict_GetItemIdWithError(f->f_locals, + if (PyDict_CheckExact(LOCALS())) { + ann_dict = _PyDict_GetItemIdWithError(LOCALS(), &PyId___annotations__); if (ann_dict == NULL) { if (_PyErr_Occurred(tstate)) { @@ -3284,7 +3289,7 @@ _PyEval_EvalFrameDefault(PyThreadState *tstate, PyFrameObject *f, int throwflag) if (ann_dict == NULL) { goto error; } - err = _PyDict_SetItemId(f->f_locals, + err = _PyDict_SetItemId(LOCALS(), &PyId___annotations__, ann_dict); Py_DECREF(ann_dict); if (err != 0) { @@ -3298,7 +3303,7 @@ _PyEval_EvalFrameDefault(PyThreadState *tstate, PyFrameObject *f, int throwflag) if (ann_str == NULL) { goto error; } - ann_dict = PyObject_GetItem(f->f_locals, ann_str); + ann_dict = PyObject_GetItem(LOCALS(), ann_str); if (ann_dict == NULL) { if (!_PyErr_ExceptionMatches(tstate, PyExc_KeyError)) { goto error; @@ -3308,7 +3313,7 @@ _PyEval_EvalFrameDefault(PyThreadState *tstate, PyFrameObject *f, int throwflag) if (ann_dict == NULL) { goto error; } - err = PyObject_SetItem(f->f_locals, ann_str, ann_dict); + err = PyObject_SetItem(LOCALS(), ann_str, ann_dict); Py_DECREF(ann_dict); if (err != 0) { goto error; @@ -3707,7 +3712,7 @@ _PyEval_EvalFrameDefault(PyThreadState *tstate, PyFrameObject *f, int throwflag) goto error; } - locals = f->f_locals; + locals = LOCALS(); if (locals == NULL) { _PyErr_SetString(tstate, PyExc_SystemError, "no locals found during 'import *'"); @@ -4313,7 +4318,7 @@ _PyEval_EvalFrameDefault(PyThreadState *tstate, PyFrameObject *f, int throwflag) PyObject *qualname = POP(); PyObject *codeobj = POP(); PyFunctionObject *func = (PyFunctionObject *) - PyFunction_NewWithQualName(codeobj, f->f_globals, qualname); + PyFunction_NewWithQualName(codeobj, GLOBALS(), qualname); Py_DECREF(codeobj); Py_DECREF(qualname); @@ -4869,25 +4874,14 @@ get_exception_handler(PyCodeObject *code, int index, int *level, int *handler, i return 0; } -PyFrameObject * -_PyEval_MakeFrameVector(PyThreadState *tstate, - PyFrameConstructor *con, PyObject *locals, - PyObject *const *args, Py_ssize_t argcount, - PyObject *kwnames) +static int +initialize_locals(PyThreadState *tstate, PyFrameConstructor *con, + PyObject **fastlocals, PyObject *const *args, + Py_ssize_t argcount, PyObject *kwnames) { - assert(is_tstate_valid(tstate)); - PyCodeObject *co = (PyCodeObject*)con->fc_code; - assert(con->fc_defaults == NULL || PyTuple_CheckExact(con->fc_defaults)); const Py_ssize_t total_args = co->co_argcount + co->co_kwonlyargcount; - - /* Create the frame */ - PyFrameObject *f = _PyFrame_New_NoTrack(tstate, con, locals); - if (f == NULL) { - return NULL; - } - PyObject **fastlocals = f->f_localsplus; - PyObject **freevars = f->f_localsplus + co->co_nlocals; + PyObject **freevars = fastlocals + co->co_nlocals; /* Create a dictionary for keyword parameters (**kwags) */ PyObject *kwdict; @@ -5093,25 +5087,33 @@ _PyEval_MakeFrameVector(PyThreadState *tstate, freevars[PyTuple_GET_SIZE(co->co_cellvars) + i] = o; } - return f; + return 0; fail: /* Jump here from prelude on failure */ + return -1; - /* 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); +} + + +PyFrameObject * +_PyEval_MakeFrameVector(PyThreadState *tstate, + PyFrameConstructor *con, PyObject *locals, + PyObject *const *args, Py_ssize_t argcount, + PyObject *kwnames, PyObject** localsarray) +{ + assert(is_tstate_valid(tstate)); + assert(con->fc_defaults == NULL || PyTuple_CheckExact(con->fc_defaults)); + + /* Create the frame */ + PyFrameObject *f = _PyFrame_New_NoTrack(tstate, con, locals, localsarray); + if (f == NULL) { + return NULL; } - else { - ++tstate->recursion_depth; + if (initialize_locals(tstate, con, f->f_localsptr, args, argcount, kwnames)) { Py_DECREF(f); - --tstate->recursion_depth; + return NULL; } - return NULL; + return f; } static PyObject * @@ -5149,30 +5151,59 @@ _PyEval_Vector(PyThreadState *tstate, PyFrameConstructor *con, PyObject* const* args, size_t argcount, PyObject *kwnames) { + PyObject **localsarray; + PyCodeObject *code = (PyCodeObject *)con->fc_code; + int is_coro = code->co_flags & + (CO_GENERATOR | CO_COROUTINE | CO_ASYNC_GENERATOR); + if (is_coro) { + localsarray = NULL; + } + else { + int size = code->co_nlocalsplus + code->co_stacksize + + FRAME_SPECIALS_SIZE; + localsarray = _PyThreadState_PushLocals(tstate, size); + if (localsarray == NULL) { + return NULL; + } + } PyFrameObject *f = _PyEval_MakeFrameVector( - tstate, con, locals, args, argcount, kwnames); + tstate, con, locals, args, argcount, kwnames, localsarray); if (f == NULL) { + if (!is_coro) { + _PyThreadState_PopLocals(tstate, localsarray); + } return NULL; } - if (((PyCodeObject *)con->fc_code)->co_flags & (CO_GENERATOR | CO_COROUTINE | CO_ASYNC_GENERATOR)) { + if (is_coro) { return make_coro(con, f); } PyObject *retval = _PyEval_EvalFrame(tstate, f, 0); + assert(f->f_stackdepth == 0); /* 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. */ + assert (!is_coro); + assert(f->f_own_locals_memory == 0); if (Py_REFCNT(f) > 1) { Py_DECREF(f); _PyObject_GC_TRACK(f); + if (_PyFrame_TakeLocals(f)) { + Py_CLEAR(retval); + } } else { ++tstate->recursion_depth; + f->f_localsptr = NULL; + for (int i = 0; i < code->co_nlocalsplus + FRAME_SPECIALS_SIZE; i++) { + Py_XDECREF(localsarray[i]); + } Py_DECREF(f); --tstate->recursion_depth; } + _PyThreadState_PopLocals(tstate, localsarray); return retval; } @@ -5778,7 +5809,7 @@ _PyEval_GetBuiltins(PyThreadState *tstate) { PyFrameObject *frame = tstate->frame; if (frame != NULL) { - return frame->f_builtins; + return _PyFrame_GetBuiltins(frame); } return tstate->interp->builtins; } @@ -5819,8 +5850,10 @@ PyEval_GetLocals(void) return NULL; } - assert(current_frame->f_locals != NULL); - return current_frame->f_locals; + PyObject *locals = current_frame->f_valuestack[ + FRAME_SPECIALS_LOCALS_OFFSET-FRAME_SPECIALS_SIZE]; + assert(locals != NULL); + return locals; } PyObject * @@ -5831,9 +5864,7 @@ PyEval_GetGlobals(void) if (current_frame == NULL) { return NULL; } - - assert(current_frame->f_globals != NULL); - return current_frame->f_globals; + return _PyFrame_GetGlobals(current_frame); } int @@ -6084,14 +6115,15 @@ import_name(PyThreadState *tstate, PyFrameObject *f, PyObject *import_func, *res; PyObject* stack[5]; - import_func = _PyDict_GetItemIdWithError(f->f_builtins, &PyId___import__); + import_func = _PyDict_GetItemIdWithError(_PyFrame_GetBuiltins(f), &PyId___import__); if (import_func == NULL) { if (!_PyErr_Occurred(tstate)) { _PyErr_SetString(tstate, PyExc_ImportError, "__import__ not found"); } return NULL; } - + PyObject *locals = f->f_valuestack[ + FRAME_SPECIALS_LOCALS_OFFSET-FRAME_SPECIALS_SIZE]; /* Fast path for not overloaded __import__. */ if (import_func == tstate->interp->import_func) { int ilevel = _PyLong_AsInt(level); @@ -6100,8 +6132,8 @@ import_name(PyThreadState *tstate, PyFrameObject *f, } res = PyImport_ImportModuleLevelObject( name, - f->f_globals, - f->f_locals == NULL ? Py_None : f->f_locals, + _PyFrame_GetGlobals(f), + locals == NULL ? Py_None :locals, fromlist, ilevel); return res; @@ -6110,8 +6142,8 @@ import_name(PyThreadState *tstate, PyFrameObject *f, Py_INCREF(import_func); stack[0] = name; - stack[1] = f->f_globals; - stack[2] = f->f_locals == NULL ? Py_None : f->f_locals; + stack[1] = _PyFrame_GetGlobals(f); + stack[2] = locals == NULL ? Py_None : locals; stack[3] = fromlist; stack[4] = level; res = _PyObject_FastCall(import_func, stack, 5); @@ -6436,14 +6468,14 @@ unicode_concatenate(PyThreadState *tstate, PyObject *v, PyObject *w, switch (opcode) { case STORE_FAST: { - PyObject **fastlocals = f->f_localsplus; + PyObject **fastlocals = f->f_localsptr; if (GETLOCAL(oparg) == v) SETLOCAL(oparg, NULL); break; } case STORE_DEREF: { - PyObject **freevars = (f->f_localsplus + + PyObject **freevars = (f->f_localsptr + f->f_code->co_nlocals); PyObject *c = freevars[oparg]; if (PyCell_GET(c) == v) { @@ -6456,7 +6488,8 @@ unicode_concatenate(PyThreadState *tstate, PyObject *v, PyObject *w, { PyObject *names = f->f_code->co_names; PyObject *name = GETITEM(names, oparg); - PyObject *locals = f->f_locals; + PyObject *locals = f->f_valuestack[ + FRAME_SPECIALS_LOCALS_OFFSET-FRAME_SPECIALS_SIZE]; if (locals && PyDict_CheckExact(locals)) { PyObject *w = PyDict_GetItemWithError(locals, name); if ((w == v && PyDict_DelItem(locals, name) != 0) || |