From fb2c54cc3c51d5e663ec24fd19dabb277e05a936 Mon Sep 17 00:00:00 2001 From: Mark Shannon Date: Tue, 24 Aug 2021 11:38:27 +0100 Subject: [PATCH 1/6] Add a few inline functions to improve encapsulation. --- Include/internal/pycore_frame.h | 26 +++++++++++++++++++++++--- Python/ceval.c | 25 ++++++++++++++----------- 2 files changed, 37 insertions(+), 14 deletions(-) diff --git a/Include/internal/pycore_frame.h b/Include/internal/pycore_frame.h index cd465d73bc6bdb..b44c4db13f9416 100644 --- a/Include/internal/pycore_frame.h +++ b/Include/internal/pycore_frame.h @@ -35,18 +35,26 @@ typedef struct _interpreter_frame { PyObject *stack[1]; } InterpreterFrame; -static inline int _PyFrame_IsRunnable(InterpreterFrame *f) { +static inline int +_PyFrame_IsRunnable(InterpreterFrame *f) { return f->f_state < FRAME_EXECUTING; } -static inline int _PyFrame_IsExecuting(InterpreterFrame *f) { +static inline int +_PyFrame_IsExecuting(InterpreterFrame *f) { return f->f_state == FRAME_EXECUTING; } -static inline int _PyFrameHasCompleted(InterpreterFrame *f) { +static inline int +_PyFrameHasCompleted(InterpreterFrame *f) { return f->f_state > FRAME_EXECUTING; } +static inline PyObject ** +_PyFrame_Stackbase(InterpreterFrame *f) { + return &f->stack[0]; +} + #define FRAME_SPECIALS_SIZE ((sizeof(InterpreterFrame)-1)/sizeof(PyObject *)) InterpreterFrame * @@ -78,6 +86,18 @@ _PyFrame_GetLocalsArray(InterpreterFrame *frame) return ((PyObject **)frame) - frame->nlocalsplus; } +static inline PyObject** +_PyFrame_GetStackPointer(InterpreterFrame *frame) +{ + return frame->stack+frame->stackdepth; +} + +static inline void +_PyFrame_SetStackPointer(InterpreterFrame *frame, PyObject **stack_pointer) +{ + frame->stackdepth = (int)(stack_pointer - frame->stack); +} + /* For use by _PyFrame_GetFrameObject Do not call directly. */ PyFrameObject * diff --git a/Python/ceval.c b/Python/ceval.c index 333c54f50e2e3a..6620985182123b 100644 --- a/Python/ceval.c +++ b/Python/ceval.c @@ -1367,7 +1367,7 @@ eval_frame_handle_pending(PyThreadState *tstate) /* The stack can grow at most MAXINT deep, as co_nlocals and co_stacksize are ints. */ -#define STACK_LEVEL() ((int)(stack_pointer - frame->stack)) +#define STACK_LEVEL() ((int)(stack_pointer - _PyFrame_Stackbase(frame))) #define EMPTY() (STACK_LEVEL() == 0) #define TOP() (stack_pointer[-1]) #define SECOND() (stack_pointer[-2]) @@ -1578,7 +1578,7 @@ _PyEval_EvalFrameDefault(PyThreadState *tstate, InterpreterFrame *frame, int thr */ assert(frame->f_lasti >= -1); _Py_CODEUNIT *next_instr = first_instr + frame->f_lasti + 1; - PyObject **stack_pointer = frame->stack + frame->stackdepth; + PyObject **stack_pointer = _PyFrame_GetStackPointer(frame); /* Set stackdepth to -1. * Update when returning or calling trace function. Having f_stackdepth <= 0 ensures that invalid @@ -1668,7 +1668,7 @@ _PyEval_EvalFrameDefault(PyThreadState *tstate, InterpreterFrame *frame, int thr int err; /* see maybe_call_line_trace() for expository comments */ - frame->stackdepth = (int)(stack_pointer - frame->stack); + _PyFrame_SetStackPointer(frame, stack_pointer); err = maybe_call_line_trace(tstate->c_tracefunc, tstate->c_traceobj, @@ -1679,7 +1679,8 @@ _PyEval_EvalFrameDefault(PyThreadState *tstate, InterpreterFrame *frame, int thr } /* Reload possibly changed frame fields */ JUMPTO(frame->f_lasti); - stack_pointer = frame->stack+frame->stackdepth; + + stack_pointer = _PyFrame_GetStackPointer(frame); frame->stackdepth = -1; TRACING_NEXTOPARG(); } @@ -2439,7 +2440,7 @@ _PyEval_EvalFrameDefault(PyThreadState *tstate, InterpreterFrame *frame, int thr retval = POP(); assert(EMPTY()); frame->f_state = FRAME_RETURNED; - frame->stackdepth = 0; + _PyFrame_SetStackPointer(frame, stack_pointer); goto exiting; } @@ -2627,7 +2628,7 @@ _PyEval_EvalFrameDefault(PyThreadState *tstate, InterpreterFrame *frame, int thr assert(frame->f_lasti > 0); frame->f_lasti -= 1; frame->f_state = FRAME_SUSPENDED; - frame->stackdepth = (int)(stack_pointer - frame->stack); + _PyFrame_SetStackPointer(frame, stack_pointer); goto exiting; } @@ -2644,7 +2645,7 @@ _PyEval_EvalFrameDefault(PyThreadState *tstate, InterpreterFrame *frame, int thr retval = w; } frame->f_state = FRAME_SUSPENDED; - frame->stackdepth = (int)(stack_pointer - frame->stack); + _PyFrame_SetStackPointer(frame, stack_pointer); goto exiting; } @@ -4346,7 +4347,7 @@ _PyEval_EvalFrameDefault(PyThreadState *tstate, InterpreterFrame *frame, int thr oparg = cache->adaptive.original_oparg; STAT_DEC(LOAD_METHOD, unquickened); JUMP_TO_INSTRUCTION(LOAD_METHOD); - } + } } TARGET(LOAD_METHOD_CACHED): { @@ -4364,7 +4365,7 @@ _PyEval_EvalFrameDefault(PyThreadState *tstate, InterpreterFrame *frame, int thr assert(cache1->tp_version != 0); assert(self_cls->tp_dictoffset >= 0); assert(Py_TYPE(self_cls)->tp_dictoffset > 0); - + // inline version of _PyObject_GetDictPtr for offset >= 0 PyObject *dict = self_cls->tp_dictoffset != 0 ? *(PyObject **) ((char *)self + self_cls->tp_dictoffset) : NULL; @@ -4821,13 +4822,15 @@ MISS_WITH_OPARG_COUNTER(BINARY_SUBSCR) PyObject *o = POP(); Py_XDECREF(o); } - frame->stackdepth = 0; + assert(STACK_LEVEL() == 0); + _PyFrame_SetStackPointer(frame, stack_pointer); frame->f_state = FRAME_RAISED; goto exiting; } assert(STACK_LEVEL() >= level); - while (STACK_LEVEL() > level) { + PyObject **new_top = _PyFrame_Stackbase(frame) + level; + while (stack_pointer > new_top) { PyObject *v = POP(); Py_XDECREF(v); } From 6ff7d3229197ddc7ddeed3e066f7949bee194ae7 Mon Sep 17 00:00:00 2001 From: Mark Shannon Date: Tue, 24 Aug 2021 14:45:29 +0100 Subject: [PATCH 2/6] Move locals to come after specials and linkage in evaluation frames. --- Include/internal/pycore_frame.h | 35 +++++++++++++++++++++++++-------- Objects/frameobject.c | 24 +++++++--------------- Objects/genobject.c | 10 +++------- Python/ceval.c | 17 ++++++++-------- Python/frame.c | 31 ++++++++++++----------------- Python/pystate.c | 20 +++++++++---------- 6 files changed, 68 insertions(+), 69 deletions(-) diff --git a/Include/internal/pycore_frame.h b/Include/internal/pycore_frame.h index b44c4db13f9416..36fd2198eb43c0 100644 --- a/Include/internal/pycore_frame.h +++ b/Include/internal/pycore_frame.h @@ -29,10 +29,10 @@ typedef struct _interpreter_frame { PyObject *generator; struct _interpreter_frame *previous; int f_lasti; /* Last instruction if called */ - int stackdepth; /* Depth of value stack */ + int stacktop; /* Offset of TOS from localsplus */ int nlocalsplus; - PyFrameState f_state; /* What state the frame is in */ - PyObject *stack[1]; + PyFrameState f_state; /* What state the frame is in */ + PyObject *localsplus[1]; } InterpreterFrame; static inline int @@ -52,7 +52,26 @@ _PyFrameHasCompleted(InterpreterFrame *f) { static inline PyObject ** _PyFrame_Stackbase(InterpreterFrame *f) { - return &f->stack[0]; + return f->localsplus + f->nlocalsplus; +} + +static inline PyObject * +_PyFrame_StackPeek(InterpreterFrame *f) { + assert(f->stacktop > f->nlocalsplus); + return f->localsplus[f->stacktop-1]; +} + +static inline PyObject * +_PyFrame_StackPop(InterpreterFrame *f) { + assert(f->stacktop > f->nlocalsplus); + f->stacktop--; + return f->localsplus[f->stacktop]; +} + +static inline void +_PyFrame_StackPush(InterpreterFrame *f, PyObject *value) { + f->localsplus[f->stacktop] = value; + f->stacktop++; } #define FRAME_SPECIALS_SIZE ((sizeof(InterpreterFrame)-1)/sizeof(PyObject *)) @@ -70,7 +89,7 @@ _PyFrame_InitializeSpecials( frame->f_globals = Py_NewRef(con->fc_globals); frame->f_locals = Py_XNewRef(locals); frame->nlocalsplus = nlocalsplus; - frame->stackdepth = 0; + frame->stacktop = nlocalsplus; frame->frame_obj = NULL; frame->generator = NULL; frame->f_lasti = -1; @@ -83,19 +102,19 @@ _PyFrame_InitializeSpecials( static inline PyObject** _PyFrame_GetLocalsArray(InterpreterFrame *frame) { - return ((PyObject **)frame) - frame->nlocalsplus; + return frame->localsplus; } static inline PyObject** _PyFrame_GetStackPointer(InterpreterFrame *frame) { - return frame->stack+frame->stackdepth; + return frame->localsplus+frame->stacktop; } static inline void _PyFrame_SetStackPointer(InterpreterFrame *frame, PyObject **stack_pointer) { - frame->stackdepth = (int)(stack_pointer - frame->stack); + frame->stacktop = (int)(stack_pointer - frame->localsplus); } /* For use by _PyFrame_GetFrameObject diff --git a/Objects/frameobject.c b/Objects/frameobject.c index 2af69597c396ee..00d6888ff2a2ac 100644 --- a/Objects/frameobject.c +++ b/Objects/frameobject.c @@ -397,9 +397,7 @@ first_line_not_before(int *lines, int len, int line) static void frame_stack_pop(PyFrameObject *f) { - assert(f->f_frame->stackdepth > 0); - f->f_frame->stackdepth--; - PyObject *v = f->f_frame->stack[f->f_frame->stackdepth]; + PyObject *v = _PyFrame_StackPop(f->f_frame); Py_DECREF(v); } @@ -633,14 +631,10 @@ frame_dealloc(PyFrameObject *f) Py_CLEAR(frame->f_builtins); Py_CLEAR(frame->f_locals); PyObject **locals = _PyFrame_GetLocalsArray(frame); - for (int i = 0; i < co->co_nlocalsplus; i++) { + for (int i = 0; i < frame->stacktop; i++) { Py_CLEAR(locals[i]); } - /* stack */ - for (int i = 0; i < frame->stackdepth; i++) { - Py_CLEAR(frame->stack[i]); - } - PyMem_Free(locals); + PyMem_Free(frame); } Py_CLEAR(f->f_back); Py_CLEAR(f->f_trace); @@ -686,17 +680,13 @@ frame_tp_clear(PyFrameObject *f) Py_CLEAR(f->f_trace); - /* locals */ + /* locals and stack */ PyObject **locals = _PyFrame_GetLocalsArray(f->f_frame); - for (int i = 0; i < f->f_frame->nlocalsplus; i++) { + assert(f->f_frame->stacktop >= 0); + for (int i = 0; i < f->f_frame->stacktop; i++) { Py_CLEAR(locals[i]); } - - /* stack */ - for (int i = 0; i < f->f_frame->stackdepth; i++) { - Py_CLEAR(f->f_frame->stack[i]); - } - f->f_frame->stackdepth = 0; + f->f_frame->stacktop = 0; return 0; } diff --git a/Objects/genobject.c b/Objects/genobject.c index 86cd9cf7254589..7a687ce7f7cdfb 100644 --- a/Objects/genobject.c +++ b/Objects/genobject.c @@ -190,8 +190,7 @@ gen_send_ex2(PyGenObject *gen, PyObject *arg, PyObject **presult, /* Push arg onto the frame's value stack */ result = arg ? arg : Py_None; Py_INCREF(result); - frame->stack[frame->stackdepth] = result; - frame->stackdepth++; + _PyFrame_StackPush(frame, result); frame->previous = tstate->frame; @@ -350,8 +349,7 @@ _PyGen_yf(PyGenObject *gen) if (code[(frame->f_lasti+1)*sizeof(_Py_CODEUNIT)] != YIELD_FROM) return NULL; - assert(frame->stackdepth > 0); - yf = frame->stack[frame->stackdepth-1]; + yf = _PyFrame_StackPeek(frame); Py_INCREF(yf); } @@ -469,9 +467,7 @@ _gen_throw(PyGenObject *gen, int close_on_genexit, if (!ret) { PyObject *val; /* Pop subiterator from stack */ - assert(gen->gi_xframe->stackdepth > 0); - gen->gi_xframe->stackdepth--; - ret = gen->gi_xframe->stack[gen->gi_xframe->stackdepth]; + ret = _PyFrame_StackPop(gen->gi_xframe); assert(ret == yf); Py_DECREF(ret); /* Termination repetition of YIELD_FROM */ diff --git a/Python/ceval.c b/Python/ceval.c index 6620985182123b..c0af2697d3943d 100644 --- a/Python/ceval.c +++ b/Python/ceval.c @@ -1581,11 +1581,11 @@ _PyEval_EvalFrameDefault(PyThreadState *tstate, InterpreterFrame *frame, int thr PyObject **stack_pointer = _PyFrame_GetStackPointer(frame); /* Set stackdepth to -1. * Update when returning or calling trace function. - Having f_stackdepth <= 0 ensures that invalid + Having stackdepth <= 0 ensures that invalid values are not visible to the cycle GC. We choose -1 rather than 0 to assist debugging. */ - frame->stackdepth = -1; + frame->stacktop = -1; frame->f_state = FRAME_EXECUTING; #ifdef LLTRACE @@ -1681,7 +1681,7 @@ _PyEval_EvalFrameDefault(PyThreadState *tstate, InterpreterFrame *frame, int thr JUMPTO(frame->f_lasti); stack_pointer = _PyFrame_GetStackPointer(frame); - frame->stackdepth = -1; + frame->stacktop = -1; TRACING_NEXTOPARG(); } PRE_DISPATCH_GOTO(); @@ -5410,18 +5410,17 @@ make_coro_frame(PyThreadState *tstate, assert(con->fc_defaults == NULL || PyTuple_CheckExact(con->fc_defaults)); PyCodeObject *code = (PyCodeObject *)con->fc_code; int size = code->co_nlocalsplus+code->co_stacksize + FRAME_SPECIALS_SIZE; - PyObject **localsarray = PyMem_Malloc(sizeof(PyObject *)*size); - if (localsarray == NULL) { + InterpreterFrame *frame = (InterpreterFrame *)PyMem_Malloc(sizeof(PyObject *)*size); + if (frame == NULL) { PyErr_NoMemory(); return NULL; } for (Py_ssize_t i=0; i < code->co_nlocalsplus; i++) { - localsarray[i] = NULL; + frame->localsplus[i] = NULL; } - InterpreterFrame *frame = (InterpreterFrame *)(localsarray + code->co_nlocalsplus); _PyFrame_InitializeSpecials(frame, con, locals, code->co_nlocalsplus); assert(frame->frame_obj == NULL); - if (initialize_locals(tstate, con, localsarray, args, argcount, kwnames)) { + if (initialize_locals(tstate, con, frame->localsplus, args, argcount, kwnames)) { _PyFrame_Clear(frame, 1); return NULL; } @@ -5500,7 +5499,7 @@ _PyEval_Vector(PyThreadState *tstate, PyFrameConstructor *con, } assert (tstate->interp->eval_frame != NULL); PyObject *retval = _PyEval_EvalFrame(tstate, frame, 0); - assert(frame->stackdepth == 0); + assert(_PyFrame_GetStackPointer(frame) == _PyFrame_Stackbase(frame)); if (_PyEvalFrameClearAndPop(tstate, frame)) { retval = NULL; } diff --git a/Python/frame.c b/Python/frame.c index ae4284346ea12f..62c3f178a03fe2 100644 --- a/Python/frame.c +++ b/Python/frame.c @@ -14,12 +14,13 @@ _PyFrame_Traverse(InterpreterFrame *frame, visitproc visit, void *arg) Py_VISIT(frame->f_code); /* locals */ PyObject **locals = _PyFrame_GetLocalsArray(frame); - for (int i = 0; i < frame->nlocalsplus; i++) { + int i = 0; + for (; i < frame->nlocalsplus; i++) { Py_VISIT(locals[i]); } /* stack */ - for (int i = 0; i stackdepth; i++) { - Py_VISIT(frame->stack[i]); + for (; i stacktop; i++) { + Py_VISIT(locals[i]); } return 0; } @@ -47,17 +48,15 @@ _PyFrame_MakeAndSetFrameObject(InterpreterFrame *frame) static InterpreterFrame * copy_frame_to_heap(InterpreterFrame *frame) { - - Py_ssize_t size = ((char*)&frame->stack[frame->stackdepth]) - (char *)_PyFrame_GetLocalsArray(frame); - PyObject **copy = PyMem_Malloc(size); + assert(frame->stacktop >= frame->nlocalsplus); + Py_ssize_t size = ((char*)&frame->localsplus[frame->stacktop]) - (char *)frame; + InterpreterFrame *copy = PyMem_Malloc(size); if (copy == NULL) { PyErr_NoMemory(); return NULL; } - PyObject **locals = _PyFrame_GetLocalsArray(frame); - memcpy(copy, locals, size); - InterpreterFrame *res = (InterpreterFrame *)(copy + frame->nlocalsplus); - return res; + memcpy(copy, frame, size); + return copy; } static inline void @@ -103,7 +102,6 @@ take_ownership(PyFrameObject *f, InterpreterFrame *frame) int _PyFrame_Clear(InterpreterFrame * frame, int take) { - PyObject **localsarray = ((PyObject **)frame)-frame->nlocalsplus; if (frame->frame_obj) { PyFrameObject *f = frame->frame_obj; frame->frame_obj = NULL; @@ -120,16 +118,13 @@ _PyFrame_Clear(InterpreterFrame * frame, int take) } Py_DECREF(f); } - for (int i = 0; i < frame->nlocalsplus; i++) { - Py_XDECREF(localsarray[i]); - } - assert(frame->stackdepth >= 0); - for (int i = 0; i < frame->stackdepth; i++) { - Py_DECREF(frame->stack[i]); + assert(_PyFrame_GetStackPointer(frame) >= _PyFrame_Stackbase(frame)); + for (int i = 0; i < frame->stacktop; i++) { + Py_XDECREF(frame->localsplus[i]); } clear_specials(frame); if (take) { - PyMem_Free(_PyFrame_GetLocalsArray(frame)); + PyMem_Free(frame); } return 0; } diff --git a/Python/pystate.c b/Python/pystate.c index 6a15b54d1dd84f..45272142e41734 100644 --- a/Python/pystate.c +++ b/Python/pystate.c @@ -2045,21 +2045,21 @@ _PyThreadState_PushFrame(PyThreadState *tstate, PyFrameConstructor *con, PyObjec size_t size = nlocalsplus + code->co_stacksize + FRAME_SPECIALS_SIZE; assert(size < INT_MAX/sizeof(PyObject *)); - PyObject **localsarray = tstate->datastack_top; - PyObject **top = localsarray + size; + PyObject **base = tstate->datastack_top; + PyObject **top = base + size; if (top >= tstate->datastack_limit) { - localsarray = push_chunk(tstate, (int)size); - if (localsarray == NULL) { + base = push_chunk(tstate, (int)size); + if (base == NULL) { return NULL; } } else { tstate->datastack_top = top; } - InterpreterFrame * frame = (InterpreterFrame *)(localsarray + nlocalsplus); + InterpreterFrame *frame = (InterpreterFrame *)base; _PyFrame_InitializeSpecials(frame, con, locals, nlocalsplus); for (int i=0; i < nlocalsplus; i++) { - localsarray[i] = NULL; + frame->localsplus[i] = NULL; } return frame; } @@ -2067,8 +2067,8 @@ _PyThreadState_PushFrame(PyThreadState *tstate, PyFrameConstructor *con, PyObjec void _PyThreadState_PopFrame(PyThreadState *tstate, InterpreterFrame * frame) { - PyObject **locals = _PyFrame_GetLocalsArray(frame); - if (locals == &tstate->datastack_chunk->data[0]) { + PyObject **base = (PyObject **)frame; + if (base == &tstate->datastack_chunk->data[0]) { _PyStackChunk *chunk = tstate->datastack_chunk; _PyStackChunk *previous = chunk->previous; tstate->datastack_top = &previous->data[previous->top]; @@ -2077,8 +2077,8 @@ _PyThreadState_PopFrame(PyThreadState *tstate, InterpreterFrame * frame) tstate->datastack_limit = (PyObject **)(((char *)previous) + previous->size); } else { - assert(tstate->datastack_top >= locals); - tstate->datastack_top = locals; + assert(tstate->datastack_top >= base); + tstate->datastack_top = base; } } From dfbf163a9bccd07d8bca080d021cc43c24452648 Mon Sep 17 00:00:00 2001 From: Mark Shannon Date: Tue, 24 Aug 2021 14:58:13 +0100 Subject: [PATCH 3/6] Fix up gdb handling of frames. --- Tools/gdb/libpython.py | 6 ++++-- 1 file changed, 4 insertions(+), 2 deletions(-) diff --git a/Tools/gdb/libpython.py b/Tools/gdb/libpython.py index 8b09563c18c9b1..c11b23e74b9bed 100755 --- a/Tools/gdb/libpython.py +++ b/Tools/gdb/libpython.py @@ -958,9 +958,11 @@ def iter_locals(self): if self.is_optimized_out(): return + obj_ptr_ptr = gdb.lookup_type("PyObject").pointer().pointer() - base = self._gdbval.cast(obj_ptr_ptr) - localsplus = base - self._f_nlocalsplus() + + localsplus = self._gdbval["localsplus"].cast(obj_ptr_ptr) + for i in safe_range(self.co_nlocals): pyop_value = PyObjectPtr.from_pyobject_ptr(localsplus[i]) if pyop_value.is_null(): From 8c5d26a3e08399934a566ddb9db72526c97d399f Mon Sep 17 00:00:00 2001 From: Mark Shannon Date: Tue, 24 Aug 2021 15:05:16 +0100 Subject: [PATCH 4/6] Remove nlocalsplus field from evaluation frame. --- Include/internal/pycore_frame.h | 8 +++----- Objects/typeobject.c | 2 +- Python/ceval.c | 3 ++- Python/frame.c | 7 ++----- 4 files changed, 8 insertions(+), 12 deletions(-) diff --git a/Include/internal/pycore_frame.h b/Include/internal/pycore_frame.h index 36fd2198eb43c0..6bb9d59d706f14 100644 --- a/Include/internal/pycore_frame.h +++ b/Include/internal/pycore_frame.h @@ -30,7 +30,6 @@ typedef struct _interpreter_frame { struct _interpreter_frame *previous; int f_lasti; /* Last instruction if called */ int stacktop; /* Offset of TOS from localsplus */ - int nlocalsplus; PyFrameState f_state; /* What state the frame is in */ PyObject *localsplus[1]; } InterpreterFrame; @@ -52,18 +51,18 @@ _PyFrameHasCompleted(InterpreterFrame *f) { static inline PyObject ** _PyFrame_Stackbase(InterpreterFrame *f) { - return f->localsplus + f->nlocalsplus; + return f->localsplus + f->f_code->co_nlocalsplus; } static inline PyObject * _PyFrame_StackPeek(InterpreterFrame *f) { - assert(f->stacktop > f->nlocalsplus); + assert(f->stacktop > f->f_code->co_nlocalsplus); return f->localsplus[f->stacktop-1]; } static inline PyObject * _PyFrame_StackPop(InterpreterFrame *f) { - assert(f->stacktop > f->nlocalsplus); + assert(f->stacktop > f->f_code->co_nlocalsplus); f->stacktop--; return f->localsplus[f->stacktop]; } @@ -88,7 +87,6 @@ _PyFrame_InitializeSpecials( frame->f_builtins = Py_NewRef(con->fc_builtins); frame->f_globals = Py_NewRef(con->fc_globals); frame->f_locals = Py_XNewRef(locals); - frame->nlocalsplus = nlocalsplus; frame->stacktop = nlocalsplus; frame->frame_obj = NULL; frame->generator = NULL; diff --git a/Objects/typeobject.c b/Objects/typeobject.c index a38690aed5c818..ec274a025de30c 100644 --- a/Objects/typeobject.c +++ b/Objects/typeobject.c @@ -8874,7 +8874,7 @@ super_init_without_args(PyFrameObject *f, PyCodeObject *co, return -1; } - assert(f->f_frame->nlocalsplus > 0); + assert(f->f_frame->f_code->co_nlocalsplus > 0); PyObject *firstarg = _PyFrame_GetLocalsArray(f->f_frame)[0]; // The first argument might be a cell. if (firstarg != NULL && (_PyLocals_GetKind(co->co_localspluskinds, 0) & CO_FAST_CELL)) { diff --git a/Python/ceval.c b/Python/ceval.c index c0af2697d3943d..c65469eff7b27c 100644 --- a/Python/ceval.c +++ b/Python/ceval.c @@ -4818,7 +4818,8 @@ MISS_WITH_OPARG_COUNTER(BINARY_SUBSCR) assert(_PyErr_Occurred(tstate)); /* Pop remaining stack entries. */ - while (!EMPTY()) { + PyObject **stackbase = _PyFrame_Stackbase(frame); + while (stack_pointer > stackbase) { PyObject *o = POP(); Py_XDECREF(o); } diff --git a/Python/frame.c b/Python/frame.c index 62c3f178a03fe2..3d2415fee70978 100644 --- a/Python/frame.c +++ b/Python/frame.c @@ -15,10 +15,7 @@ _PyFrame_Traverse(InterpreterFrame *frame, visitproc visit, void *arg) /* locals */ PyObject **locals = _PyFrame_GetLocalsArray(frame); int i = 0; - for (; i < frame->nlocalsplus; i++) { - Py_VISIT(locals[i]); - } - /* stack */ + /* locals and stack */ for (; i stacktop; i++) { Py_VISIT(locals[i]); } @@ -48,7 +45,7 @@ _PyFrame_MakeAndSetFrameObject(InterpreterFrame *frame) static InterpreterFrame * copy_frame_to_heap(InterpreterFrame *frame) { - assert(frame->stacktop >= frame->nlocalsplus); + assert(frame->stacktop >= frame->f_code->co_nlocalsplus); Py_ssize_t size = ((char*)&frame->localsplus[frame->stacktop]) - (char *)frame; InterpreterFrame *copy = PyMem_Malloc(size); if (copy == NULL) { From dbad8a1c65d0fe40e3c05a61d86bfc10221df86f Mon Sep 17 00:00:00 2001 From: Mark Shannon Date: Tue, 24 Aug 2021 15:32:00 +0100 Subject: [PATCH 5/6] Remove localsplus variable from the interpreter. Local variables are now at a fixed offset in the frame. --- Python/ceval.c | 31 ++++++++++++++++--------------- 1 file changed, 16 insertions(+), 15 deletions(-) diff --git a/Python/ceval.c b/Python/ceval.c index c65469eff7b27c..5fec90b10483ab 100644 --- a/Python/ceval.c +++ b/Python/ceval.c @@ -1413,7 +1413,7 @@ eval_frame_handle_pending(PyThreadState *tstate) /* Local variable macros */ -#define GETLOCAL(i) (localsplus[i]) +#define GETLOCAL(i) (frame->localsplus[i]) /* The SETLOCAL() macro must not DECREF the local variable in-place and then store the new value; it must copy the old value to a temporary @@ -1559,7 +1559,6 @@ _PyEval_EvalFrameDefault(PyThreadState *tstate, InterpreterFrame *frame, int thr PyObject *names = co->co_names; PyObject *consts = co->co_consts; - PyObject **localsplus = _PyFrame_GetLocalsArray(frame); _Py_CODEUNIT *first_instr = co->co_firstinstr; /* frame->f_lasti refers to the index of the last instruction, @@ -4985,7 +4984,7 @@ missing_arguments(PyThreadState *tstate, PyCodeObject *co, end = start + co->co_kwonlyargcount; } for (i = start; i < end; i++) { - if (GETLOCAL(i) == NULL) { + if (localsplus[i] == NULL) { PyObject *raw = PyTuple_GET_ITEM(co->co_localsplusnames, i); PyObject *name = PyObject_Repr(raw); if (name == NULL) { @@ -5014,7 +5013,7 @@ too_many_positional(PyThreadState *tstate, PyCodeObject *co, assert((co->co_flags & CO_VARARGS) == 0); /* Count missing keyword-only args. */ for (i = co_argcount; i < co_argcount + co->co_kwonlyargcount; i++) { - if (GETLOCAL(i) != NULL) { + if (localsplus[i] != NULL) { kwonly_given++; } } @@ -5221,7 +5220,8 @@ initialize_locals(PyThreadState *tstate, PyFrameConstructor *con, if (co->co_flags & CO_VARARGS) { i++; } - SETLOCAL(i, kwdict); + assert(localsplus[i] == NULL); + localsplus[i] = kwdict; } else { kwdict = NULL; @@ -5238,7 +5238,8 @@ initialize_locals(PyThreadState *tstate, PyFrameConstructor *con, for (j = 0; j < n; j++) { PyObject *x = args[j]; Py_INCREF(x); - SETLOCAL(j, x); + assert(localsplus[j] == NULL); + localsplus[j] = x; } /* Pack other positional arguments into the *args argument */ @@ -5247,7 +5248,8 @@ initialize_locals(PyThreadState *tstate, PyFrameConstructor *con, if (u == NULL) { goto fail; } - SETLOCAL(total_args, u); + assert(localsplus[total_args] == NULL); + localsplus[total_args] = u; } /* Handle keyword arguments */ @@ -5311,14 +5313,14 @@ initialize_locals(PyThreadState *tstate, PyFrameConstructor *con, continue; kw_found: - if (GETLOCAL(j) != NULL) { + if (localsplus[j] != NULL) { _PyErr_Format(tstate, PyExc_TypeError, "%U() got multiple values for argument '%S'", con->fc_qualname, keyword); goto fail; } Py_INCREF(value); - SETLOCAL(j, value); + localsplus[j] = value; } } @@ -5335,7 +5337,7 @@ initialize_locals(PyThreadState *tstate, PyFrameConstructor *con, Py_ssize_t m = co->co_argcount - defcount; Py_ssize_t missing = 0; for (i = argcount; i < m; i++) { - if (GETLOCAL(i) == NULL) { + if (localsplus[i] == NULL) { missing++; } } @@ -5351,10 +5353,10 @@ initialize_locals(PyThreadState *tstate, PyFrameConstructor *con, if (defcount) { PyObject **defs = &PyTuple_GET_ITEM(con->fc_defaults, 0); for (; i < defcount; i++) { - if (GETLOCAL(m+i) == NULL) { + if (localsplus[m+i] == NULL) { PyObject *def = defs[i]; Py_INCREF(def); - SETLOCAL(m+i, def); + localsplus[m+i] = def; } } } @@ -5364,14 +5366,14 @@ initialize_locals(PyThreadState *tstate, PyFrameConstructor *con, if (co->co_kwonlyargcount > 0) { Py_ssize_t missing = 0; for (i = co->co_argcount; i < total_args; i++) { - if (GETLOCAL(i) != NULL) + if (localsplus[i] != NULL) continue; PyObject *varname = PyTuple_GET_ITEM(co->co_localsplusnames, i); if (con->fc_kwdefaults != NULL) { PyObject *def = PyDict_GetItemWithError(con->fc_kwdefaults, varname); if (def) { Py_INCREF(def); - SETLOCAL(i, def); + localsplus[i] = def; continue; } else if (_PyErr_Occurred(tstate)) { @@ -6767,7 +6769,6 @@ unicode_concatenate(PyThreadState *tstate, PyObject *v, PyObject *w, switch (opcode) { case STORE_FAST: { - PyObject **localsplus = _PyFrame_GetLocalsArray(frame); if (GETLOCAL(oparg) == v) SETLOCAL(oparg, NULL); break; From 2682c5f860e31636af09e2df4afe38333fb0bec4 Mon Sep 17 00:00:00 2001 From: Mark Shannon Date: Wed, 25 Aug 2021 12:40:59 +0100 Subject: [PATCH 6/6] Tidy up some inline functions --- Include/internal/pycore_frame.h | 21 +++++++-------------- 1 file changed, 7 insertions(+), 14 deletions(-) diff --git a/Include/internal/pycore_frame.h b/Include/internal/pycore_frame.h index 6bb9d59d706f14..6afb95c3ad62e0 100644 --- a/Include/internal/pycore_frame.h +++ b/Include/internal/pycore_frame.h @@ -34,41 +34,34 @@ typedef struct _interpreter_frame { PyObject *localsplus[1]; } InterpreterFrame; -static inline int -_PyFrame_IsRunnable(InterpreterFrame *f) { +static inline int _PyFrame_IsRunnable(InterpreterFrame *f) { return f->f_state < FRAME_EXECUTING; } -static inline int -_PyFrame_IsExecuting(InterpreterFrame *f) { +static inline int _PyFrame_IsExecuting(InterpreterFrame *f) { return f->f_state == FRAME_EXECUTING; } -static inline int -_PyFrameHasCompleted(InterpreterFrame *f) { +static inline int _PyFrameHasCompleted(InterpreterFrame *f) { return f->f_state > FRAME_EXECUTING; } -static inline PyObject ** -_PyFrame_Stackbase(InterpreterFrame *f) { +static inline PyObject **_PyFrame_Stackbase(InterpreterFrame *f) { return f->localsplus + f->f_code->co_nlocalsplus; } -static inline PyObject * -_PyFrame_StackPeek(InterpreterFrame *f) { +static inline PyObject *_PyFrame_StackPeek(InterpreterFrame *f) { assert(f->stacktop > f->f_code->co_nlocalsplus); return f->localsplus[f->stacktop-1]; } -static inline PyObject * -_PyFrame_StackPop(InterpreterFrame *f) { +static inline PyObject *_PyFrame_StackPop(InterpreterFrame *f) { assert(f->stacktop > f->f_code->co_nlocalsplus); f->stacktop--; return f->localsplus[f->stacktop]; } -static inline void -_PyFrame_StackPush(InterpreterFrame *f, PyObject *value) { +static inline void _PyFrame_StackPush(InterpreterFrame *f, PyObject *value) { f->localsplus[f->stacktop] = value; f->stacktop++; }