[Python-checkins] bpo-44990: Change layout of evaluation frames. "Layout B" (GH-27933)

markshannon webhook-mailer at python.org
Wed Aug 25 08:44:29 EDT 2021


https://github.com/python/cpython/commit/f9242d50b18572ef0d584a1c815ed08d1a38e4f4
commit: f9242d50b18572ef0d584a1c815ed08d1a38e4f4
branch: main
author: Mark Shannon <mark at hotpy.org>
committer: markshannon <mark at hotpy.org>
date: 2021-08-25T13:44:20+01:00
summary:

bpo-44990: Change layout of evaluation frames. "Layout B" (GH-27933)

Places the locals between the specials and stack. This is the more "natural" layout for a C struct, makes the code simpler and gives a slight speedup (~1%)

files:
M Include/internal/pycore_frame.h
M Objects/frameobject.c
M Objects/genobject.c
M Objects/typeobject.c
M Python/ceval.c
M Python/frame.c
M Python/pystate.c
M Tools/gdb/libpython.py

diff --git a/Include/internal/pycore_frame.h b/Include/internal/pycore_frame.h
index cd465d73bc6bdb..6afb95c3ad62e0 100644
--- a/Include/internal/pycore_frame.h
+++ b/Include/internal/pycore_frame.h
@@ -29,10 +29,9 @@ typedef struct _interpreter_frame {
     PyObject *generator;
     struct _interpreter_frame *previous;
     int f_lasti;       /* Last instruction if called */
-    int stackdepth;  /* Depth of value stack */
-    int nlocalsplus;
-    PyFrameState f_state;       /* What state the frame is in */
-    PyObject *stack[1];
+    int stacktop;     /* Offset of TOS from localsplus  */
+    PyFrameState f_state;  /* What state the frame is in */
+    PyObject *localsplus[1];
 } InterpreterFrame;
 
 static inline int _PyFrame_IsRunnable(InterpreterFrame *f) {
@@ -47,6 +46,26 @@ static inline int _PyFrameHasCompleted(InterpreterFrame *f) {
     return f->f_state > FRAME_EXECUTING;
 }
 
+static inline PyObject **_PyFrame_Stackbase(InterpreterFrame *f) {
+    return f->localsplus + f->f_code->co_nlocalsplus;
+}
+
+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) {
+    assert(f->stacktop > f->f_code->co_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 *))
 
 InterpreterFrame *
@@ -61,8 +80,7 @@ _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->stackdepth = 0;
+    frame->stacktop = nlocalsplus;
     frame->frame_obj = NULL;
     frame->generator = NULL;
     frame->f_lasti = -1;
@@ -75,7 +93,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->localsplus+frame->stacktop;
+}
+
+static inline void
+_PyFrame_SetStackPointer(InterpreterFrame *frame, PyObject **stack_pointer)
+{
+    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/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 333c54f50e2e3a..5fec90b10483ab 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])
@@ -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,
@@ -1578,14 +1577,14 @@ _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
+       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
@@ -1668,7 +1667,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,8 +1678,9 @@ _PyEval_EvalFrameDefault(PyThreadState *tstate, InterpreterFrame *frame, int thr
             }
             /* Reload possibly changed frame fields */
             JUMPTO(frame->f_lasti);
-            stack_pointer = frame->stack+frame->stackdepth;
-            frame->stackdepth = -1;
+
+            stack_pointer = _PyFrame_GetStackPointer(frame);
+            frame->stacktop = -1;
             TRACING_NEXTOPARG();
         }
         PRE_DISPATCH_GOTO();
@@ -2439,7 +2439,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 +2627,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 +2644,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 +4346,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 +4364,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;
@@ -4817,17 +4817,20 @@ 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);
             }
-            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);
         }
@@ -4981,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) {
@@ -5010,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++;
         }
     }
@@ -5217,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;
@@ -5234,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 */
@@ -5243,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 */
@@ -5307,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;
         }
     }
 
@@ -5331,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++;
             }
         }
@@ -5347,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;
                 }
             }
         }
@@ -5360,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)) {
@@ -5407,18 +5413,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;
     }
@@ -5497,7 +5502,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;
     }
@@ -6764,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;
diff --git a/Python/frame.c b/Python/frame.c
index ae4284346ea12f..3d2415fee70978 100644
--- a/Python/frame.c
+++ b/Python/frame.c
@@ -14,13 +14,11 @@ _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;
+    /* locals and stack */
+    for (; i <frame->stacktop; i++) {
         Py_VISIT(locals[i]);
     }
-    /* stack */
-    for (int i = 0; i <frame->stackdepth; i++) {
-        Py_VISIT(frame->stack[i]);
-    }
     return 0;
 }
 
@@ -47,17 +45,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->f_code->co_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 +99,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 +115,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;
     }
 }
 
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():



More information about the Python-checkins mailing list