Skip to content

Commit a7e7f75

Browse files
committed
Replace stack pointer with depth in PyFrameObject. Makes code easier to read and saves a word of memory.
1 parent 0d4d7e4 commit a7e7f75

File tree

5 files changed

+28
-38
lines changed

5 files changed

+28
-38
lines changed

Include/cpython/frameobject.h

Lines changed: 1 addition & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -28,11 +28,8 @@ struct _frame {
2828
PyObject *f_globals; /* global symbol table (PyDictObject) */
2929
PyObject *f_locals; /* local symbol table (any mapping) */
3030
PyObject **f_valuestack; /* points after the last local */
31-
/* Next free slot in f_valuestack. Frame creation sets to f_valuestack.
32-
Frame evaluation usually NULLs it, but a frame that yields sets it
33-
to the current stack top. */
34-
PyObject **f_stacktop;
3531
PyObject *f_trace; /* Trace function */
32+
int f_stackdepth; /* Depth of value stack */
3633
char f_trace_lines; /* Emit per-line trace events? */
3734
char f_trace_opcodes; /* Emit per-opcode trace events? */
3835

Lib/test/test_sys.py

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1236,7 +1236,7 @@ class C(object): pass
12361236
nfrees = len(x.f_code.co_freevars)
12371237
extras = x.f_code.co_stacksize + x.f_code.co_nlocals +\
12381238
ncells + nfrees - 1
1239-
check(x, vsize('5P2c4P3ic' + CO_MAXBLOCKS*'3i' + 'P' + extras*'P'))
1239+
check(x, vsize('4Pi2c4P3ic' + CO_MAXBLOCKS*'3i' + 'P' + extras*'P'))
12401240
# function
12411241
def func(): pass
12421242
check(func, size('13P'))

Objects/frameobject.c

Lines changed: 12 additions & 17 deletions
Original file line numberDiff line numberDiff line change
@@ -300,7 +300,8 @@ first_line_not_before(int *lines, int len, int line)
300300
static void
301301
frame_stack_pop(PyFrameObject *f)
302302
{
303-
PyObject *v = (*--f->f_stacktop);
303+
f->f_stackdepth--;
304+
PyObject *v = f->f_valuestack[f->f_stackdepth];
304305
Py_DECREF(v);
305306
}
306307

@@ -310,7 +311,7 @@ frame_block_unwind(PyFrameObject *f)
310311
assert(f->f_iblock > 0);
311312
f->f_iblock--;
312313
PyTryBlock *b = &f->f_blockstack[f->f_iblock];
313-
intptr_t delta = (f->f_stacktop - f->f_valuestack) - b->b_level;
314+
intptr_t delta = f->f_stackdepth - b->b_level;
314315
while (delta > 0) {
315316
frame_stack_pop(f);
316317
delta--;
@@ -584,11 +585,10 @@ frame_dealloc(PyFrameObject *f)
584585
}
585586

586587
/* Free stack */
587-
if (f->f_stacktop != NULL) {
588-
for (PyObject **p = valuestack; p < f->f_stacktop; p++) {
589-
Py_XDECREF(*p);
590-
}
588+
for (int i = 0; i < f->f_stackdepth; i++) {
589+
Py_XDECREF(f->f_valuestack[i]);
591590
}
591+
f->f_stackdepth = 0;
592592

593593
Py_XDECREF(f->f_back);
594594
Py_DECREF(f->f_builtins);
@@ -646,10 +646,8 @@ frame_traverse(PyFrameObject *f, visitproc visit, void *arg)
646646
}
647647

648648
/* stack */
649-
if (f->f_stacktop != NULL) {
650-
for (PyObject **p = f->f_valuestack; p < f->f_stacktop; p++) {
651-
Py_VISIT(*p);
652-
}
649+
for (int i = 0; i < f->f_stackdepth; i++) {
650+
Py_VISIT(f->f_valuestack[i]);
653651
}
654652
return 0;
655653
}
@@ -662,8 +660,6 @@ frame_tp_clear(PyFrameObject *f)
662660
* frame may also point to this frame, believe itself to still be
663661
* active, and try cleaning up this frame again.
664662
*/
665-
PyObject **oldtop = f->f_stacktop;
666-
f->f_stacktop = NULL;
667663
f->f_state = FRAME_CLEARED;
668664

669665
Py_CLEAR(f->f_trace);
@@ -675,11 +671,10 @@ frame_tp_clear(PyFrameObject *f)
675671
}
676672

677673
/* stack */
678-
if (oldtop != NULL) {
679-
for (PyObject **p = f->f_valuestack; p < oldtop; p++) {
680-
Py_CLEAR(*p);
681-
}
674+
for (int i = 0; i < f->f_stackdepth; i++) {
675+
Py_CLEAR(f->f_valuestack[i]);
682676
}
677+
f->f_stackdepth = 0;
683678
return 0;
684679
}
685680

@@ -897,7 +892,7 @@ _PyFrame_New_NoTrack(PyThreadState *tstate, PyCodeObject *code,
897892
return NULL;
898893
}
899894

900-
f->f_stacktop = f->f_valuestack;
895+
f->f_stackdepth = 0;
901896
f->f_builtins = builtins;
902897
Py_XINCREF(back);
903898
f->f_back = back;

Objects/genobject.c

Lines changed: 7 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -195,7 +195,8 @@ gen_send_ex(PyGenObject *gen, PyObject *arg, int exc, int closing)
195195
/* Push arg onto the frame's value stack */
196196
result = arg ? arg : Py_None;
197197
Py_INCREF(result);
198-
*(f->f_stacktop++) = result;
198+
gen->gi_frame->f_valuestack[gen->gi_frame->f_stackdepth] = result;
199+
gen->gi_frame->f_stackdepth++;
199200
}
200201

201202
/* Generators always return to their most recent caller, not
@@ -326,7 +327,7 @@ _PyGen_yf(PyGenObject *gen)
326327
PyObject *yf = NULL;
327328
PyFrameObject *f = gen->gi_frame;
328329

329-
if (f && f->f_stacktop) {
330+
if (f) {
330331
PyObject *bytecode = f->f_code->co_code;
331332
unsigned char *code = (unsigned char *)PyBytes_AS_STRING(bytecode);
332333

@@ -340,7 +341,8 @@ _PyGen_yf(PyGenObject *gen)
340341

341342
if (code[f->f_lasti + sizeof(_Py_CODEUNIT)] != YIELD_FROM)
342343
return NULL;
343-
yf = f->f_stacktop[-1];
344+
assert(f->f_stackdepth > 0);
345+
yf = f->f_valuestack[f->f_stackdepth-1];
344346
Py_INCREF(yf);
345347
}
346348

@@ -454,7 +456,8 @@ _gen_throw(PyGenObject *gen, int close_on_genexit,
454456
if (!ret) {
455457
PyObject *val;
456458
/* Pop subiterator from stack */
457-
ret = *(--gen->gi_frame->f_stacktop);
459+
gen->gi_frame->f_stackdepth--;
460+
ret = gen->gi_frame->f_valuestack[gen->gi_frame->f_stackdepth];
458461
assert(ret == yf);
459462
Py_DECREF(ret);
460463
/* Termination repetition of YIELD_FROM */

Python/ceval.c

Lines changed: 7 additions & 12 deletions
Original file line numberDiff line numberDiff line change
@@ -1349,10 +1349,10 @@ _PyEval_EvalFrameDefault(PyThreadState *tstate, PyFrameObject *f, int throwflag)
13491349
assert(f->f_lasti % sizeof(_Py_CODEUNIT) == 0);
13501350
next_instr += f->f_lasti / sizeof(_Py_CODEUNIT) + 1;
13511351
}
1352-
f->f_state = FRAME_EXECUTING;
1353-
stack_pointer = f->f_stacktop;
1354-
assert(stack_pointer != NULL);
1355-
f->f_stacktop = NULL; /* remains NULL unless yield suspends frame */
1352+
stack_pointer = f->f_valuestack + f->f_stackdepth;
1353+
/* To help with debugging, set f->f_stackdepth to -1.
1354+
* Update when returning or calling trace function */
1355+
f->f_stackdepth = -1;
13561356
f->f_state = FRAME_EXECUTING;
13571357

13581358
if (co->co_opcache_flag < OPCACHE_MIN_RUNS) {
@@ -1441,18 +1441,15 @@ _PyEval_EvalFrameDefault(PyThreadState *tstate, PyFrameObject *f, int throwflag)
14411441
int err;
14421442
/* see maybe_call_line_trace
14431443
for expository comments */
1444-
f->f_stacktop = stack_pointer;
1444+
f->f_stackdepth = stack_pointer-f->f_valuestack;
14451445

14461446
err = maybe_call_line_trace(tstate->c_tracefunc,
14471447
tstate->c_traceobj,
14481448
tstate, f,
14491449
&instr_lb, &instr_ub, &instr_prev);
14501450
/* Reload possibly changed frame fields */
14511451
JUMPTO(f->f_lasti);
1452-
if (f->f_stacktop != NULL) {
1453-
stack_pointer = f->f_stacktop;
1454-
f->f_stacktop = NULL;
1455-
}
1452+
stack_pointer = f->f_valuestack+f->f_stackdepth;
14561453
if (err)
14571454
/* trace function raised an exception */
14581455
goto error;
@@ -2244,7 +2241,6 @@ _PyEval_EvalFrameDefault(PyThreadState *tstate, PyFrameObject *f, int throwflag)
22442241
DISPATCH();
22452242
}
22462243
/* receiver remains on stack, retval is value to be yielded */
2247-
f->f_stacktop = stack_pointer;
22482244
/* and repeat... */
22492245
assert(f->f_lasti >= (int)sizeof(_Py_CODEUNIT));
22502246
f->f_lasti -= sizeof(_Py_CODEUNIT);
@@ -2264,8 +2260,6 @@ _PyEval_EvalFrameDefault(PyThreadState *tstate, PyFrameObject *f, int throwflag)
22642260
}
22652261
retval = w;
22662262
}
2267-
2268-
f->f_stacktop = stack_pointer;
22692263
f->f_state = FRAME_SUSPENDED;
22702264
goto exiting;
22712265
}
@@ -3852,6 +3846,7 @@ _PyEval_EvalFrameDefault(PyThreadState *tstate, PyFrameObject *f, int throwflag)
38523846

38533847
f->f_state = FRAME_RAISED;
38543848
exiting:
3849+
f->f_stackdepth = stack_pointer-f->f_valuestack;
38553850
if (tstate->use_tracing) {
38563851
if (tstate->c_tracefunc) {
38573852
if (call_trace_protected(tstate->c_tracefunc, tstate->c_traceobj,

0 commit comments

Comments
 (0)