@@ -6,6 +6,7 @@ extern "C" {
6
6
7
7
#include <stdbool.h>
8
8
#include <stddef.h>
9
+ #include "pycore_code.h" // STATS
9
10
10
11
/* See Objects/frame_layout.md for an explanation of the frame stack
11
12
* including explanation of the PyFrameObject and _PyInterpreterFrame
@@ -48,22 +49,26 @@ enum _frameowner {
48
49
};
49
50
50
51
typedef struct _PyInterpreterFrame {
51
- /* "Specials" section */
52
- PyFunctionObject * f_func ; /* Strong reference */
53
- PyObject * f_globals ; /* Borrowed reference */
54
- PyObject * f_builtins ; /* Borrowed reference */
55
- PyObject * f_locals ; /* Strong reference, may be NULL */
56
52
PyCodeObject * f_code ; /* Strong reference */
57
- PyFrameObject * frame_obj ; /* Strong reference, may be NULL */
58
- /* Linkage section */
59
53
struct _PyInterpreterFrame * previous ;
54
+ PyObject * f_funcobj ; /* Strong reference. Only valid if not on C stack */
55
+ PyObject * f_globals ; /* Borrowed reference. Only valid if not on C stack */
56
+ PyObject * f_builtins ; /* Borrowed reference. Only valid if not on C stack */
57
+ PyObject * f_locals ; /* Strong reference, may be NULL. Only valid if not on C stack */
58
+ PyFrameObject * frame_obj ; /* Strong reference, may be NULL. Only valid if not on C stack */
60
59
// NOTE: This is not necessarily the last instruction started in the given
61
60
// frame. Rather, it is the code unit *prior to* the *next* instruction. For
62
61
// example, it may be an inline CACHE entry, an instruction we just jumped
63
62
// over, or (in the case of a newly-created frame) a totally invalid value:
64
63
_Py_CODEUNIT * prev_instr ;
65
- int stacktop ; /* Offset of TOS from localsplus */
66
- bool is_entry ; // Whether this is the "root" frame for the current _PyCFrame.
64
+ int stacktop ; /* Offset of TOS from localsplus */
65
+ /* The return_offset determines where a `RETURN` should go in the caller,
66
+ * relative to `prev_instr`.
67
+ * It is only meaningful to the callee,
68
+ * so it needs to be set in any CALL (to a Python function)
69
+ * or SEND (to a coroutine or generator).
70
+ * If there is no callee, then it is meaningless. */
71
+ uint16_t return_offset ;
67
72
char owner ;
68
73
/* Locals and stack */
69
74
PyObject * localsplus [1 ];
@@ -93,7 +98,16 @@ static inline void _PyFrame_StackPush(_PyInterpreterFrame *f, PyObject *value) {
93
98
f -> stacktop ++ ;
94
99
}
95
100
96
- #define FRAME_SPECIALS_SIZE ((sizeof(_PyInterpreterFrame)-1)/sizeof(PyObject *))
101
+ #define FRAME_SPECIALS_SIZE ((int)((sizeof(_PyInterpreterFrame)-1)/sizeof(PyObject *)))
102
+
103
+ static inline int
104
+ _PyFrame_NumSlotsForCodeObject (PyCodeObject * code )
105
+ {
106
+ /* This function needs to remain in sync with the calculation of
107
+ * co_framesize in Tools/build/deepfreeze.py */
108
+ assert (code -> co_framesize >= FRAME_SPECIALS_SIZE );
109
+ return code -> co_framesize - FRAME_SPECIALS_SIZE ;
110
+ }
97
111
98
112
void _PyFrame_Copy (_PyInterpreterFrame * src , _PyInterpreterFrame * dest );
99
113
@@ -102,20 +116,24 @@ void _PyFrame_Copy(_PyInterpreterFrame *src, _PyInterpreterFrame *dest);
102
116
when frame is linked into the frame stack.
103
117
*/
104
118
static inline void
105
- _PyFrame_InitializeSpecials (
119
+ _PyFrame_Initialize (
106
120
_PyInterpreterFrame * frame , PyFunctionObject * func ,
107
- PyObject * locals , int nlocalsplus )
121
+ PyObject * locals , PyCodeObject * code , int null_locals_from )
108
122
{
109
- frame -> f_func = func ;
110
- frame -> f_code = (PyCodeObject * )Py_NewRef (func -> func_code );
123
+ frame -> f_funcobj = ( PyObject * ) func ;
124
+ frame -> f_code = (PyCodeObject * )Py_NewRef (code );
111
125
frame -> f_builtins = func -> func_builtins ;
112
126
frame -> f_globals = func -> func_globals ;
113
- frame -> f_locals = Py_XNewRef ( locals ) ;
114
- frame -> stacktop = nlocalsplus ;
127
+ frame -> f_locals = locals ;
128
+ frame -> stacktop = code -> co_nlocalsplus ;
115
129
frame -> frame_obj = NULL ;
116
- frame -> prev_instr = _PyCode_CODE (frame -> f_code ) - 1 ;
117
- frame -> is_entry = false ;
130
+ frame -> prev_instr = _PyCode_CODE (code ) - 1 ;
131
+ frame -> return_offset = 0 ;
118
132
frame -> owner = FRAME_OWNED_BY_THREAD ;
133
+
134
+ for (int i = null_locals_from ; i < code -> co_nlocalsplus ; i ++ ) {
135
+ frame -> localsplus [i ] = NULL ;
136
+ }
119
137
}
120
138
121
139
/* Gets the pointer to the locals array
@@ -127,10 +145,16 @@ _PyFrame_GetLocalsArray(_PyInterpreterFrame *frame)
127
145
return frame -> localsplus ;
128
146
}
129
147
148
+ /* Fetches the stack pointer, and sets stacktop to -1.
149
+ Having stacktop <= 0 ensures that invalid
150
+ values are not visible to the cycle GC.
151
+ We choose -1 rather than 0 to assist debugging. */
130
152
static inline PyObject * *
131
153
_PyFrame_GetStackPointer (_PyInterpreterFrame * frame )
132
154
{
133
- return frame -> localsplus + frame -> stacktop ;
155
+ PyObject * * sp = frame -> localsplus + frame -> stacktop ;
156
+ frame -> stacktop = -1 ;
157
+ return sp ;
134
158
}
135
159
136
160
static inline void
@@ -154,6 +178,21 @@ _PyFrame_IsIncomplete(_PyInterpreterFrame *frame)
154
178
frame -> prev_instr < _PyCode_CODE (frame -> f_code ) + frame -> f_code -> _co_firsttraceable ;
155
179
}
156
180
181
+ static inline _PyInterpreterFrame *
182
+ _PyFrame_GetFirstComplete (_PyInterpreterFrame * frame )
183
+ {
184
+ while (frame && _PyFrame_IsIncomplete (frame )) {
185
+ frame = frame -> previous ;
186
+ }
187
+ return frame ;
188
+ }
189
+
190
+ static inline _PyInterpreterFrame *
191
+ _PyThreadState_GetFrame (PyThreadState * tstate )
192
+ {
193
+ return _PyFrame_GetFirstComplete (tstate -> cframe -> current_frame );
194
+ }
195
+
157
196
/* For use by _PyFrame_GetFrameObject
158
197
Do not call directly. */
159
198
PyFrameObject *
@@ -184,50 +223,51 @@ _PyFrame_GetFrameObject(_PyInterpreterFrame *frame)
184
223
* frames like the ones in generators and coroutines.
185
224
*/
186
225
void
187
- _PyFrame_Clear (_PyInterpreterFrame * frame );
226
+ _PyFrame_ClearExceptCode (_PyInterpreterFrame * frame );
188
227
189
228
int
190
229
_PyFrame_Traverse (_PyInterpreterFrame * frame , visitproc visit , void * arg );
191
230
231
+ PyObject *
232
+ _PyFrame_GetLocals (_PyInterpreterFrame * frame , int include_hidden );
233
+
192
234
int
193
235
_PyFrame_FastToLocalsWithError (_PyInterpreterFrame * frame );
194
236
195
237
void
196
238
_PyFrame_LocalsToFast (_PyInterpreterFrame * frame , int clear );
197
239
198
- extern _PyInterpreterFrame *
199
- _PyThreadState_BumpFramePointerSlow (PyThreadState * tstate , size_t size );
200
-
201
240
static inline bool
202
- _PyThreadState_HasStackSpace (PyThreadState * tstate , size_t size )
241
+ _PyThreadState_HasStackSpace (PyThreadState * tstate , int size )
203
242
{
204
243
assert (
205
244
(tstate -> datastack_top == NULL && tstate -> datastack_limit == NULL )
206
245
||
207
246
(tstate -> datastack_top != NULL && tstate -> datastack_limit != NULL )
208
247
);
209
248
return tstate -> datastack_top != NULL &&
210
- size < ( size_t )( tstate -> datastack_limit - tstate -> datastack_top ) ;
249
+ size < tstate -> datastack_limit - tstate -> datastack_top ;
211
250
}
212
251
213
- static inline _PyInterpreterFrame *
214
- _PyThreadState_BumpFramePointer (PyThreadState * tstate , size_t size )
215
- {
216
- if (_PyThreadState_HasStackSpace (tstate , size )) {
217
- _PyInterpreterFrame * res = (_PyInterpreterFrame * )tstate -> datastack_top ;
218
- tstate -> datastack_top += size ;
219
- return res ;
220
- }
221
- return _PyThreadState_BumpFramePointerSlow (tstate , size );
222
- }
252
+ extern _PyInterpreterFrame *
253
+ _PyThreadState_PushFrame (PyThreadState * tstate , size_t size );
223
254
224
255
void _PyThreadState_PopFrame (PyThreadState * tstate , _PyInterpreterFrame * frame );
225
256
226
- /* Consume reference to func */
227
- _PyInterpreterFrame *
228
- _PyFrame_Push (PyThreadState * tstate , PyFunctionObject * func );
229
-
230
- int _PyInterpreterFrame_GetLine (_PyInterpreterFrame * frame );
257
+ /* Pushes a frame without checking for space.
258
+ * Must be guarded by _PyThreadState_HasStackSpace()
259
+ * Consumes reference to func. */
260
+ static inline _PyInterpreterFrame *
261
+ _PyFrame_PushUnchecked (PyThreadState * tstate , PyFunctionObject * func , int null_locals_from )
262
+ {
263
+ CALL_STAT_INC (frames_pushed );
264
+ PyCodeObject * code = (PyCodeObject * )func -> func_code ;
265
+ _PyInterpreterFrame * new_frame = (_PyInterpreterFrame * )tstate -> datastack_top ;
266
+ tstate -> datastack_top += code -> co_framesize ;
267
+ assert (tstate -> datastack_top < tstate -> datastack_limit );
268
+ _PyFrame_Initialize (new_frame , func , NULL , code , null_locals_from );
269
+ return new_frame ;
270
+ }
231
271
232
272
static inline
233
273
PyGenObject * _PyFrame_GetGenerator (_PyInterpreterFrame * frame )
0 commit comments