Skip to content

Commit f9242d5

Browse files
authored
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%)
1 parent 214c2e5 commit f9242d5

File tree

8 files changed

+114
-100
lines changed

8 files changed

+114
-100
lines changed

Include/internal/pycore_frame.h

+37-7
Original file line numberDiff line numberDiff line change
@@ -29,10 +29,9 @@ typedef struct _interpreter_frame {
2929
PyObject *generator;
3030
struct _interpreter_frame *previous;
3131
int f_lasti; /* Last instruction if called */
32-
int stackdepth; /* Depth of value stack */
33-
int nlocalsplus;
34-
PyFrameState f_state; /* What state the frame is in */
35-
PyObject *stack[1];
32+
int stacktop; /* Offset of TOS from localsplus */
33+
PyFrameState f_state; /* What state the frame is in */
34+
PyObject *localsplus[1];
3635
} InterpreterFrame;
3736

3837
static inline int _PyFrame_IsRunnable(InterpreterFrame *f) {
@@ -47,6 +46,26 @@ static inline int _PyFrameHasCompleted(InterpreterFrame *f) {
4746
return f->f_state > FRAME_EXECUTING;
4847
}
4948

49+
static inline PyObject **_PyFrame_Stackbase(InterpreterFrame *f) {
50+
return f->localsplus + f->f_code->co_nlocalsplus;
51+
}
52+
53+
static inline PyObject *_PyFrame_StackPeek(InterpreterFrame *f) {
54+
assert(f->stacktop > f->f_code->co_nlocalsplus);
55+
return f->localsplus[f->stacktop-1];
56+
}
57+
58+
static inline PyObject *_PyFrame_StackPop(InterpreterFrame *f) {
59+
assert(f->stacktop > f->f_code->co_nlocalsplus);
60+
f->stacktop--;
61+
return f->localsplus[f->stacktop];
62+
}
63+
64+
static inline void _PyFrame_StackPush(InterpreterFrame *f, PyObject *value) {
65+
f->localsplus[f->stacktop] = value;
66+
f->stacktop++;
67+
}
68+
5069
#define FRAME_SPECIALS_SIZE ((sizeof(InterpreterFrame)-1)/sizeof(PyObject *))
5170

5271
InterpreterFrame *
@@ -61,8 +80,7 @@ _PyFrame_InitializeSpecials(
6180
frame->f_builtins = Py_NewRef(con->fc_builtins);
6281
frame->f_globals = Py_NewRef(con->fc_globals);
6382
frame->f_locals = Py_XNewRef(locals);
64-
frame->nlocalsplus = nlocalsplus;
65-
frame->stackdepth = 0;
83+
frame->stacktop = nlocalsplus;
6684
frame->frame_obj = NULL;
6785
frame->generator = NULL;
6886
frame->f_lasti = -1;
@@ -75,7 +93,19 @@ _PyFrame_InitializeSpecials(
7593
static inline PyObject**
7694
_PyFrame_GetLocalsArray(InterpreterFrame *frame)
7795
{
78-
return ((PyObject **)frame) - frame->nlocalsplus;
96+
return frame->localsplus;
97+
}
98+
99+
static inline PyObject**
100+
_PyFrame_GetStackPointer(InterpreterFrame *frame)
101+
{
102+
return frame->localsplus+frame->stacktop;
103+
}
104+
105+
static inline void
106+
_PyFrame_SetStackPointer(InterpreterFrame *frame, PyObject **stack_pointer)
107+
{
108+
frame->stacktop = (int)(stack_pointer - frame->localsplus);
79109
}
80110

81111
/* For use by _PyFrame_GetFrameObject

Objects/frameobject.c

+7-17
Original file line numberDiff line numberDiff line change
@@ -397,9 +397,7 @@ first_line_not_before(int *lines, int len, int line)
397397
static void
398398
frame_stack_pop(PyFrameObject *f)
399399
{
400-
assert(f->f_frame->stackdepth > 0);
401-
f->f_frame->stackdepth--;
402-
PyObject *v = f->f_frame->stack[f->f_frame->stackdepth];
400+
PyObject *v = _PyFrame_StackPop(f->f_frame);
403401
Py_DECREF(v);
404402
}
405403

@@ -633,14 +631,10 @@ frame_dealloc(PyFrameObject *f)
633631
Py_CLEAR(frame->f_builtins);
634632
Py_CLEAR(frame->f_locals);
635633
PyObject **locals = _PyFrame_GetLocalsArray(frame);
636-
for (int i = 0; i < co->co_nlocalsplus; i++) {
634+
for (int i = 0; i < frame->stacktop; i++) {
637635
Py_CLEAR(locals[i]);
638636
}
639-
/* stack */
640-
for (int i = 0; i < frame->stackdepth; i++) {
641-
Py_CLEAR(frame->stack[i]);
642-
}
643-
PyMem_Free(locals);
637+
PyMem_Free(frame);
644638
}
645639
Py_CLEAR(f->f_back);
646640
Py_CLEAR(f->f_trace);
@@ -686,17 +680,13 @@ frame_tp_clear(PyFrameObject *f)
686680

687681
Py_CLEAR(f->f_trace);
688682

689-
/* locals */
683+
/* locals and stack */
690684
PyObject **locals = _PyFrame_GetLocalsArray(f->f_frame);
691-
for (int i = 0; i < f->f_frame->nlocalsplus; i++) {
685+
assert(f->f_frame->stacktop >= 0);
686+
for (int i = 0; i < f->f_frame->stacktop; i++) {
692687
Py_CLEAR(locals[i]);
693688
}
694-
695-
/* stack */
696-
for (int i = 0; i < f->f_frame->stackdepth; i++) {
697-
Py_CLEAR(f->f_frame->stack[i]);
698-
}
699-
f->f_frame->stackdepth = 0;
689+
f->f_frame->stacktop = 0;
700690
return 0;
701691
}
702692

Objects/genobject.c

+3-7
Original file line numberDiff line numberDiff line change
@@ -190,8 +190,7 @@ gen_send_ex2(PyGenObject *gen, PyObject *arg, PyObject **presult,
190190
/* Push arg onto the frame's value stack */
191191
result = arg ? arg : Py_None;
192192
Py_INCREF(result);
193-
frame->stack[frame->stackdepth] = result;
194-
frame->stackdepth++;
193+
_PyFrame_StackPush(frame, result);
195194

196195
frame->previous = tstate->frame;
197196

@@ -350,8 +349,7 @@ _PyGen_yf(PyGenObject *gen)
350349

351350
if (code[(frame->f_lasti+1)*sizeof(_Py_CODEUNIT)] != YIELD_FROM)
352351
return NULL;
353-
assert(frame->stackdepth > 0);
354-
yf = frame->stack[frame->stackdepth-1];
352+
yf = _PyFrame_StackPeek(frame);
355353
Py_INCREF(yf);
356354
}
357355

@@ -469,9 +467,7 @@ _gen_throw(PyGenObject *gen, int close_on_genexit,
469467
if (!ret) {
470468
PyObject *val;
471469
/* Pop subiterator from stack */
472-
assert(gen->gi_xframe->stackdepth > 0);
473-
gen->gi_xframe->stackdepth--;
474-
ret = gen->gi_xframe->stack[gen->gi_xframe->stackdepth];
470+
ret = _PyFrame_StackPop(gen->gi_xframe);
475471
assert(ret == yf);
476472
Py_DECREF(ret);
477473
/* Termination repetition of YIELD_FROM */

Objects/typeobject.c

+1-1
Original file line numberDiff line numberDiff line change
@@ -8874,7 +8874,7 @@ super_init_without_args(PyFrameObject *f, PyCodeObject *co,
88748874
return -1;
88758875
}
88768876

8877-
assert(f->f_frame->nlocalsplus > 0);
8877+
assert(f->f_frame->f_code->co_nlocalsplus > 0);
88788878
PyObject *firstarg = _PyFrame_GetLocalsArray(f->f_frame)[0];
88798879
// The first argument might be a cell.
88808880
if (firstarg != NULL && (_PyLocals_GetKind(co->co_localspluskinds, 0) & CO_FAST_CELL)) {

0 commit comments

Comments
 (0)