@@ -17,9 +17,39 @@ extern "C" {
1717#define _PyInterpreterFrame_LASTI (IF ) \
1818 ((int)((IF)->instr_ptr - _PyFrame_GetBytecode((IF))))
1919
20+ PyAPI_DATA (PyTypeObject ) PyUnstable_ExternalExecutable_Type ;
21+
22+ #define PyUnstable_ExternalExecutable_Check (op ) Py_IS_TYPE((op), &PyUnstable_ExternalExecutable_Type)
23+
24+ // Initialize a potentially external frame and make it safe to access the
25+ // all of the members of the returned _PyInterpreterFrame. The returned
26+ // value will be the same address as the passed in pointer.
27+ PyAPI_FUNC (void ) _PyFrame_InitializeExternalFrame (_PyInterpreterFrame * frame );
28+
29+ PyAPI_FUNC (PyObject * ) PyUnstable_MakeExternalExecutable (_PyFrame_Reifier reifier , PyCodeObject * code , PyObject * state );
30+
31+ static inline bool _PyFrame_IsExternalFrame (_PyInterpreterFrame * frame )
32+ {
33+ if (PyStackRef_IsNull (frame -> f_executable )) {
34+ return false;
35+ }
36+ return PyUnstable_ExternalExecutable_Check (PyStackRef_AsPyObjectBorrow (frame -> f_executable ));
37+ }
38+
39+ static inline void
40+ _PyFrame_EnsureFrameFullyInitialized (_PyInterpreterFrame * frame )
41+ {
42+ if (_PyFrame_IsExternalFrame (frame )) {
43+ _PyFrame_InitializeExternalFrame (frame );
44+ }
45+ }
46+
2047static inline PyCodeObject * _PyFrame_GetCode (_PyInterpreterFrame * f ) {
2148 assert (!PyStackRef_IsNull (f -> f_executable ));
2249 PyObject * executable = PyStackRef_AsPyObjectBorrow (f -> f_executable );
50+ if (PyUnstable_ExternalExecutable_Check (executable )) {
51+ return ((PyUnstable_PyExternalExecutable * )executable )-> ef_code ;
52+ }
2353 assert (PyCode_Check (executable ));
2454 return (PyCodeObject * )executable ;
2555}
@@ -30,12 +60,6 @@ static inline PyCodeObject *_PyFrame_GetCode(_PyInterpreterFrame *f) {
3060static inline PyCodeObject * _Py_NO_SANITIZE_THREAD
3161_PyFrame_SafeGetCode (_PyInterpreterFrame * f )
3262{
33- // globals and builtins may be NULL on a legit frame, but it's unlikely.
34- // It's more likely that it's a sign of an invalid frame.
35- if (f -> f_globals == NULL || f -> f_builtins == NULL ) {
36- return NULL ;
37- }
38-
3963 if (PyStackRef_IsNull (f -> f_executable )) {
4064 return NULL ;
4165 }
@@ -48,6 +72,18 @@ _PyFrame_SafeGetCode(_PyInterpreterFrame *f)
4872 if (_PyObject_IsFreed (executable )) {
4973 return NULL ;
5074 }
75+ if (_PyFrame_IsExternalFrame (f )) {
76+ executable = (PyObject * )((PyUnstable_PyExternalExecutable * )executable )-> ef_code ;
77+ if (_PyObject_IsFreed (executable )) {
78+ return NULL ;
79+ }
80+ } else {
81+ // globals and builtins may be NULL on a legit frame, but it's unlikely.
82+ // It's more likely that it's a sign of an invalid frame.
83+ if (f -> f_globals == NULL || f -> f_builtins == NULL ) {
84+ return NULL ;
85+ }
86+ }
5187 if (!PyCode_Check (executable )) {
5288 return NULL ;
5389 }
@@ -81,6 +117,7 @@ _PyFrame_SafeGetLasti(struct _PyInterpreterFrame *f)
81117 }
82118
83119 _Py_CODEUNIT * bytecode ;
120+ _PyFrame_EnsureFrameFullyInitialized (f );
84121#ifdef Py_GIL_DISABLED
85122 _PyCodeArray * tlbc = _PyCode_GetTLBCArray (co );
86123 assert (f -> tlbc_index >= 0 && f -> tlbc_index < tlbc -> size );
@@ -262,6 +299,9 @@ _PyFrame_IsIncomplete(_PyInterpreterFrame *frame)
262299 if (frame -> owner >= FRAME_OWNED_BY_INTERPRETER ) {
263300 return true;
264301 }
302+ if (frame -> instr_ptr == NULL ) {
303+ return false;
304+ }
265305 return frame -> owner != FRAME_OWNED_BY_GENERATOR &&
266306 frame -> instr_ptr < _PyFrame_GetBytecode (frame ) +
267307 _PyFrame_GetCode (frame )-> _co_firsttraceable ;
@@ -276,12 +316,69 @@ _PyFrame_GetFirstComplete(_PyInterpreterFrame *frame)
276316 return frame ;
277317}
278318
319+ #if Py_DEBUG
320+
321+ static inline bool _Py_NO_SANITIZE_THREAD
322+ _PyFrame_IsIncompleteOrUninitialized (_PyInterpreterFrame * frame )
323+ {
324+ if (frame -> owner >= FRAME_OWNED_BY_INTERPRETER || _PyFrame_IsExternalFrame (frame )) {
325+ return true;
326+ }
327+ if (frame -> instr_ptr == NULL ) {
328+ return true;
329+ }
330+ return frame -> owner != FRAME_OWNED_BY_GENERATOR &&
331+ frame -> instr_ptr < _PyFrame_GetBytecode (frame ) +
332+ _PyFrame_GetCode (frame )-> _co_firsttraceable ;
333+ }
334+
335+ static inline _PyInterpreterFrame *
336+ _PyFrame_GetFirstCompleteInitialized (_PyInterpreterFrame * frame )
337+ {
338+ while (frame && _PyFrame_IsIncompleteOrUninitialized (frame )) {
339+ frame = frame -> previous ;
340+ }
341+ return frame ;
342+ }
343+
344+ #endif
345+
346+ static inline bool
347+ _PyFrame_StackpointerSaved (void )
348+ {
349+ #if Py_DEBUG
350+ PyThreadState * tstate = PyThreadState_GET ();
351+ return _PyFrame_GetFirstCompleteInitialized (tstate -> current_frame ) == NULL ||
352+ _PyFrame_GetFirstCompleteInitialized (tstate -> current_frame )-> stackpointer != NULL ;
353+ #else
354+ return true;
355+ #endif
356+ }
357+
358+
359+
279360static inline _PyInterpreterFrame *
280361_PyThreadState_GetFrame (PyThreadState * tstate )
281362{
282363 return _PyFrame_GetFirstComplete (tstate -> current_frame );
283364}
284365
366+ static inline PyObject *
367+ _PyFrame_GetGlobals (_PyInterpreterFrame * frame ) {
368+ if (frame -> f_globals == NULL ) {
369+ frame -> f_globals = _PyFrame_GetFunction (frame )-> func_globals ;
370+ }
371+ return frame -> f_globals ;
372+ }
373+
374+ static inline PyObject *
375+ _PyFrame_GetBuiltins (_PyInterpreterFrame * frame ) {
376+ if (frame -> f_builtins == NULL ) {
377+ frame -> f_builtins = _PyFrame_GetFunction (frame )-> func_builtins ;
378+ }
379+ return frame -> f_builtins ;
380+ }
381+
285382/* For use by _PyFrame_GetFrameObject
286383 Do not call directly. */
287384PyAPI_FUNC (PyFrameObject * )
@@ -293,9 +390,8 @@ _PyFrame_MakeAndSetFrameObject(_PyInterpreterFrame *frame);
293390static inline PyFrameObject *
294391_PyFrame_GetFrameObject (_PyInterpreterFrame * frame )
295392{
296-
297393 assert (!_PyFrame_IsIncomplete (frame ));
298- PyFrameObject * res = frame -> frame_obj ;
394+ PyFrameObject * res = frame -> frame_obj ;
299395 if (res != NULL ) {
300396 return res ;
301397 }
@@ -314,7 +410,7 @@ _PyFrame_ClearLocals(_PyInterpreterFrame *frame);
314410 * take should be set to 1 for heap allocated
315411 * frames like the ones in generators and coroutines.
316412 */
317- void
413+ PyAPI_FUNC ( void )
318414_PyFrame_ClearExceptCode (_PyInterpreterFrame * frame );
319415
320416int
@@ -363,7 +459,7 @@ _PyFrame_PushUnchecked(PyThreadState *tstate, _PyStackRef func, int null_locals_
363459/* Pushes a trampoline frame without checking for space.
364460 * Must be guarded by _PyThreadState_HasStackSpace() */
365461static inline _PyInterpreterFrame *
366- _PyFrame_PushTrampolineUnchecked (PyThreadState * tstate , PyCodeObject * code , int stackdepth , _PyInterpreterFrame * previous )
462+ _PyFrame_PushTrampolineUnchecked (PyThreadState * tstate , PyCodeObject * code , int stackdepth , _PyInterpreterFrame * previous )
367463{
368464 CALL_STAT_INC (frames_pushed );
369465 _PyInterpreterFrame * frame = (_PyInterpreterFrame * )tstate -> datastack_top ;
0 commit comments