Skip to content

Commit f748355

Browse files
committed
Convert stacktop to pointer
1 parent e12729e commit f748355

File tree

4 files changed

+50
-39
lines changed

4 files changed

+50
-39
lines changed

Include/internal/pycore_frame.h

Lines changed: 25 additions & 22 deletions
Original file line numberDiff line numberDiff line change
@@ -63,7 +63,7 @@ typedef struct _PyInterpreterFrame {
6363
PyObject *f_locals; /* Strong reference, may be NULL. Only valid if not on C stack */
6464
PyFrameObject *frame_obj; /* Strong reference, may be NULL. Only valid if not on C stack */
6565
_Py_CODEUNIT *instr_ptr; /* Instruction currently executing (or about to begin) */
66-
int stacktop; /* Offset of TOS from localsplus */
66+
PyObject **stackpointer;
6767
uint16_t return_offset; /* Only relevant during a function call */
6868
char owner;
6969
/* Locals and stack */
@@ -83,20 +83,20 @@ static inline PyObject **_PyFrame_Stackbase(_PyInterpreterFrame *f) {
8383
}
8484

8585
static inline PyObject *_PyFrame_StackPeek(_PyInterpreterFrame *f) {
86-
assert(f->stacktop > _PyFrame_GetCode(f)->co_nlocalsplus);
87-
assert(f->localsplus[f->stacktop-1] != NULL);
88-
return f->localsplus[f->stacktop-1];
86+
assert(f->stackpointer > f->localsplus + _PyFrame_GetCode(f)->co_nlocalsplus);
87+
assert(f->stackpointer[-1] != NULL);
88+
return f->stackpointer[-1];
8989
}
9090

9191
static inline PyObject *_PyFrame_StackPop(_PyInterpreterFrame *f) {
92-
assert(f->stacktop > _PyFrame_GetCode(f)->co_nlocalsplus);
93-
f->stacktop--;
94-
return f->localsplus[f->stacktop];
92+
assert(f->stackpointer > f->localsplus + _PyFrame_GetCode(f)->co_nlocalsplus);
93+
f->stackpointer--;
94+
return *f->stackpointer;
9595
}
9696

9797
static inline void _PyFrame_StackPush(_PyInterpreterFrame *f, PyObject *value) {
98-
f->localsplus[f->stacktop] = value;
99-
f->stacktop++;
98+
*f->stackpointer = value;
99+
f->stackpointer++;
100100
}
101101

102102
#define FRAME_SPECIALS_SIZE ((int)((sizeof(_PyInterpreterFrame)-1)/sizeof(PyObject *)))
@@ -112,9 +112,12 @@ _PyFrame_NumSlotsForCodeObject(PyCodeObject *code)
112112

113113
static inline void _PyFrame_Copy(_PyInterpreterFrame *src, _PyInterpreterFrame *dest)
114114
{
115-
assert(src->stacktop >= _PyFrame_GetCode(src)->co_nlocalsplus);
116115
*dest = *src;
117-
for (int i = 1; i < src->stacktop; i++) {
116+
assert(src->stackpointer != NULL);
117+
int stacktop = (int)(src->stackpointer - src->localsplus);
118+
assert(stacktop >= _PyFrame_GetCode(src)->co_nlocalsplus);
119+
dest->stackpointer = dest->localsplus + stacktop;
120+
for (int i = 1; i < stacktop; i++) {
118121
dest->localsplus[i] = src->localsplus[i];
119122
}
120123
// Don't leave a dangling pointer to the old frame when creating generators
@@ -136,7 +139,7 @@ _PyFrame_Initialize(
136139
frame->f_builtins = func->func_builtins;
137140
frame->f_globals = func->func_globals;
138141
frame->f_locals = locals;
139-
frame->stacktop = code->co_nlocalsplus;
142+
frame->stackpointer = frame->localsplus + code->co_nlocalsplus;
140143
frame->frame_obj = NULL;
141144
frame->instr_ptr = _PyCode_CODE(code);
142145
frame->return_offset = 0;
@@ -156,24 +159,23 @@ _PyFrame_GetLocalsArray(_PyInterpreterFrame *frame)
156159
return frame->localsplus;
157160
}
158161

159-
/* Fetches the stack pointer, and sets stacktop to -1.
160-
Having stacktop <= 0 ensures that invalid
161-
values are not visible to the cycle GC.
162-
We choose -1 rather than 0 to assist debugging. */
162+
/* Fetches the stack pointer, and sets stackpointer to NULL.
163+
Having stackpointer == NULL ensures that invalid
164+
values are not visible to the cycle GC. */
163165
static inline PyObject**
164166
_PyFrame_GetStackPointer(_PyInterpreterFrame *frame)
165167
{
166-
assert(frame->stacktop >= 0);
167-
PyObject **sp = frame->localsplus + frame->stacktop;
168-
frame->stacktop = -1;
168+
assert(frame->stackpointer != NULL);
169+
PyObject **sp = frame->stackpointer;
170+
frame->stackpointer = NULL;
169171
return sp;
170172
}
171173

172174
static inline void
173175
_PyFrame_SetStackPointer(_PyInterpreterFrame *frame, PyObject **stack_pointer)
174176
{
175-
assert(frame->stacktop == -1);
176-
frame->stacktop = (int)(stack_pointer - frame->localsplus);
177+
assert(frame->stackpointer == NULL);
178+
frame->stackpointer = stack_pointer;
177179
}
178180

179181
/* Determine whether a frame is incomplete.
@@ -301,7 +303,8 @@ _PyFrame_PushTrampolineUnchecked(PyThreadState *tstate, PyCodeObject *code, int
301303
frame->f_globals = NULL;
302304
#endif
303305
frame->f_locals = NULL;
304-
frame->stacktop = code->co_nlocalsplus + stackdepth;
306+
assert(stackdepth <= code->co_stacksize);
307+
frame->stackpointer = frame->localsplus + code->co_nlocalsplus + stackdepth;
305308
frame->frame_obj = NULL;
306309
frame->instr_ptr = _PyCode_CODE(code);
307310
frame->owner = FRAME_OWNED_BY_THREAD;

Objects/frameobject.c

Lines changed: 11 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -1619,8 +1619,10 @@ frame_dealloc(PyFrameObject *f)
16191619
Py_CLEAR(frame->f_funcobj);
16201620
Py_CLEAR(frame->f_locals);
16211621
PyObject **locals = _PyFrame_GetLocalsArray(frame);
1622-
for (int i = 0; i < frame->stacktop; i++) {
1623-
Py_CLEAR(locals[i]);
1622+
PyObject **sp = frame->stackpointer;
1623+
while (sp > locals) {
1624+
sp--;
1625+
Py_CLEAR(*sp);
16241626
}
16251627
}
16261628
Py_CLEAR(f->f_back);
@@ -1652,11 +1654,13 @@ frame_tp_clear(PyFrameObject *f)
16521654

16531655
/* locals and stack */
16541656
PyObject **locals = _PyFrame_GetLocalsArray(f->f_frame);
1655-
assert(f->f_frame->stacktop >= 0);
1656-
for (int i = 0; i < f->f_frame->stacktop; i++) {
1657-
Py_CLEAR(locals[i]);
1657+
PyObject **sp = f->f_frame->stackpointer;
1658+
assert(sp >= locals);
1659+
while (sp > locals) {
1660+
sp--;
1661+
Py_CLEAR(*sp);
16581662
}
1659-
f->f_frame->stacktop = 0;
1663+
f->f_frame->stackpointer = locals;
16601664
Py_CLEAR(f->f_frame->f_locals);
16611665
return 0;
16621666
}
@@ -1874,7 +1878,7 @@ frame_get_var(_PyInterpreterFrame *frame, PyCodeObject *co, int i,
18741878
}
18751879

18761880
PyObject *value = frame->localsplus[i];
1877-
if (frame->stacktop) {
1881+
if (frame->stackpointer > frame->localsplus) {
18781882
if (kind & CO_FAST_FREE) {
18791883
// The cell was set by COPY_FREE_VARS.
18801884
assert(value != NULL && PyCell_Check(value));

Python/ceval.c

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -719,7 +719,7 @@ _PyEval_EvalFrameDefault(PyThreadState *tstate, _PyInterpreterFrame *frame, int
719719
#endif
720720
entry_frame.f_executable = Py_None;
721721
entry_frame.instr_ptr = (_Py_CODEUNIT *)_Py_INTERPRETER_TRAMPOLINE_INSTRUCTIONS + 1;
722-
entry_frame.stacktop = 0;
722+
entry_frame.stackpointer = entry_frame.localsplus;
723723
entry_frame.owner = FRAME_OWNED_BY_CSTACK;
724724
entry_frame.return_offset = 0;
725725
/* Push frame */

Python/frame.c

Lines changed: 13 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -17,10 +17,11 @@ _PyFrame_Traverse(_PyInterpreterFrame *frame, visitproc visit, void *arg)
1717
Py_VISIT(_PyFrame_GetCode(frame));
1818
/* locals */
1919
PyObject **locals = _PyFrame_GetLocalsArray(frame);
20-
int i = 0;
20+
PyObject **sp = frame->stackpointer;
2121
/* locals and stack */
22-
for (; i <frame->stacktop; i++) {
23-
Py_VISIT(locals[i]);
22+
while (sp > locals) {
23+
sp--;
24+
Py_VISIT(*sp);
2425
}
2526
return 0;
2627
}
@@ -59,10 +60,11 @@ take_ownership(PyFrameObject *f, _PyInterpreterFrame *frame)
5960
assert(frame->owner != FRAME_OWNED_BY_CSTACK);
6061
assert(frame->owner != FRAME_OWNED_BY_FRAME_OBJECT);
6162
assert(frame->owner != FRAME_CLEARED);
62-
Py_ssize_t size = ((char*)&frame->localsplus[frame->stacktop]) - (char *)frame;
63+
Py_ssize_t size = ((char*)frame->stackpointer) - (char *)frame;
6364
Py_INCREF(_PyFrame_GetCode(frame));
6465
memcpy((_PyInterpreterFrame *)f->_f_frame_data, frame, size);
6566
frame = (_PyInterpreterFrame *)f->_f_frame_data;
67+
frame->stackpointer = (PyObject **)(((char *)frame) + size);
6668
f->f_frame = frame;
6769
frame->owner = FRAME_OWNED_BY_FRAME_OBJECT;
6870
if (_PyFrame_IsIncomplete(frame)) {
@@ -97,11 +99,13 @@ take_ownership(PyFrameObject *f, _PyInterpreterFrame *frame)
9799
void
98100
_PyFrame_ClearLocals(_PyInterpreterFrame *frame)
99101
{
100-
assert(frame->stacktop >= 0);
101-
int stacktop = frame->stacktop;
102-
frame->stacktop = 0;
103-
for (int i = 0; i < stacktop; i++) {
104-
Py_XDECREF(frame->localsplus[i]);
102+
assert(frame->stackpointer != NULL);
103+
PyObject **sp = frame->stackpointer;
104+
PyObject **locals = frame->localsplus;
105+
frame->stackpointer = locals;
106+
while (sp > locals) {
107+
sp--;
108+
Py_XDECREF(*sp);
105109
}
106110
Py_CLEAR(frame->f_locals);
107111
}

0 commit comments

Comments
 (0)