@@ -17,9 +17,37 @@ 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 bool _PyFrame_IsExternalFrame (_PyInterpreterFrame * frame )
32+ {
33+ return frame -> owner & FRAME_OWNED_EXTERNALLY ;
34+ }
35+
36+ static inline void
37+ _PyFrame_EnsureFrameFullyInitialized (_PyInterpreterFrame * frame )
38+ {
39+ if (_PyFrame_IsExternalFrame (frame )) {
40+ _PyFrame_InitializeExternalFrame (frame );
41+ }
42+ }
43+
2044static inline PyCodeObject * _PyFrame_GetCode (_PyInterpreterFrame * f ) {
2145 assert (!PyStackRef_IsNull (f -> f_executable ));
2246 PyObject * executable = PyStackRef_AsPyObjectBorrow (f -> f_executable );
47+ if (f -> owner & FRAME_OWNED_EXTERNALLY ) {
48+ assert (PyUnstable_ExternalExecutable_Check (executable ));
49+ return ((PyUnstable_PyExternalExecutable * )executable )-> ef_code ;
50+ }
2351 assert (PyCode_Check (executable ));
2452 return (PyCodeObject * )executable ;
2553}
@@ -30,12 +58,6 @@ static inline PyCodeObject *_PyFrame_GetCode(_PyInterpreterFrame *f) {
3058static inline PyCodeObject * _Py_NO_SANITIZE_THREAD
3159_PyFrame_SafeGetCode (_PyInterpreterFrame * f )
3260{
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-
3961 if (PyStackRef_IsNull (f -> f_executable )) {
4062 return NULL ;
4163 }
@@ -48,6 +70,18 @@ _PyFrame_SafeGetCode(_PyInterpreterFrame *f)
4870 if (_PyObject_IsFreed (executable )) {
4971 return NULL ;
5072 }
73+ if (_PyFrame_IsExternalFrame (f )) {
74+ executable = (PyObject * )((PyUnstable_PyExternalExecutable * )executable )-> ef_code ;
75+ if (_PyObject_IsFreed (executable )) {
76+ return NULL ;
77+ }
78+ } else {
79+ // globals and builtins may be NULL on a legit frame, but it's unlikely.
80+ // It's more likely that it's a sign of an invalid frame.
81+ if (f -> f_globals == NULL || f -> f_builtins == NULL ) {
82+ return NULL ;
83+ }
84+ }
5185 if (!PyCode_Check (executable )) {
5286 return NULL ;
5387 }
@@ -59,6 +93,7 @@ _PyFrame_GetBytecode(_PyInterpreterFrame *f)
5993{
6094#ifdef Py_GIL_DISABLED
6195 PyCodeObject * co = _PyFrame_GetCode (f );
96+ _PyFrame_EnsureFrameFullyInitialized (f );
6297 _PyCodeArray * tlbc = _PyCode_GetTLBCArray (co );
6398 assert (f -> tlbc_index >= 0 && f -> tlbc_index < tlbc -> size );
6499 return (_Py_CODEUNIT * )tlbc -> entries [f -> tlbc_index ];
@@ -81,6 +116,7 @@ _PyFrame_SafeGetLasti(struct _PyInterpreterFrame *f)
81116 }
82117
83118 _Py_CODEUNIT * bytecode ;
119+ _PyFrame_EnsureFrameFullyInitialized (f );
84120#ifdef Py_GIL_DISABLED
85121 _PyCodeArray * tlbc = _PyCode_GetTLBCArray (co );
86122 assert (f -> tlbc_index >= 0 && f -> tlbc_index < tlbc -> size );
@@ -256,10 +292,11 @@ _PyFrame_IsIncomplete(_PyInterpreterFrame *frame)
256292{
257293 if (frame -> owner >= FRAME_OWNED_BY_INTERPRETER ) {
258294 return true;
295+ } else if (frame -> owner & (FRAME_OWNED_BY_GENERATOR |FRAME_OWNED_EXTERNALLY )) {
296+ return false;
259297 }
260- return frame -> owner != FRAME_OWNED_BY_GENERATOR &&
261- frame -> instr_ptr < _PyFrame_GetBytecode (frame ) +
262- _PyFrame_GetCode (frame )-> _co_firsttraceable ;
298+ return frame -> instr_ptr < _PyFrame_GetBytecode (frame ) +
299+ _PyFrame_GetCode (frame )-> _co_firsttraceable ;
263300}
264301
265302static inline _PyInterpreterFrame *
@@ -271,12 +308,61 @@ _PyFrame_GetFirstComplete(_PyInterpreterFrame *frame)
271308 return frame ;
272309}
273310
311+ #if Py_DEBUG
312+
313+ static inline bool _Py_NO_SANITIZE_THREAD
314+ _PyFrame_IsIncompleteOrUninitialized (_PyInterpreterFrame * frame )
315+ {
316+ if (frame -> owner >= FRAME_OWNED_BY_INTERPRETER || _PyFrame_IsExternalFrame (frame )) {
317+ return true;
318+ }
319+ return !(frame -> owner & FRAME_OWNED_BY_GENERATOR ) &&
320+ frame -> instr_ptr < _PyFrame_GetBytecode (frame ) +
321+ _PyFrame_GetCode (frame )-> _co_firsttraceable ;
322+ }
323+
324+ static inline _PyInterpreterFrame *
325+ _PyFrame_GetFirstCompleteInitialized (_PyInterpreterFrame * frame )
326+ {
327+ while (frame && _PyFrame_IsIncompleteOrUninitialized (frame )) {
328+ frame = frame -> previous ;
329+ }
330+ return frame ;
331+ }
332+
333+ static inline bool
334+ _PyFrame_StackpointerSaved (void )
335+ {
336+ PyThreadState * tstate = PyThreadState_GET ();
337+ return _PyFrame_GetFirstCompleteInitialized (tstate -> current_frame ) == NULL ||
338+ _PyFrame_GetFirstCompleteInitialized (tstate -> current_frame )-> stackpointer != NULL ;
339+ }
340+
341+ #endif
342+
343+
274344static inline _PyInterpreterFrame *
275345_PyThreadState_GetFrame (PyThreadState * tstate )
276346{
277347 return _PyFrame_GetFirstComplete (tstate -> current_frame );
278348}
279349
350+ static inline PyObject *
351+ _PyFrame_GetGlobals (_PyInterpreterFrame * frame ) {
352+ if (frame -> f_globals == NULL ) {
353+ frame -> f_globals = _PyFrame_GetFunction (frame )-> func_globals ;
354+ }
355+ return frame -> f_globals ;
356+ }
357+
358+ static inline PyObject *
359+ _PyFrame_GetBuiltins (_PyInterpreterFrame * frame ) {
360+ if (frame -> f_builtins == NULL ) {
361+ frame -> f_builtins = _PyFrame_GetFunction (frame )-> func_builtins ;
362+ }
363+ return frame -> f_builtins ;
364+ }
365+
280366/* For use by _PyFrame_GetFrameObject
281367 Do not call directly. */
282368PyAPI_FUNC (PyFrameObject * )
@@ -288,9 +374,9 @@ _PyFrame_MakeAndSetFrameObject(_PyInterpreterFrame *frame);
288374static inline PyFrameObject *
289375_PyFrame_GetFrameObject (_PyInterpreterFrame * frame )
290376{
291-
377+ _PyFrame_EnsureFrameFullyInitialized ( frame );
292378 assert (!_PyFrame_IsIncomplete (frame ));
293- PyFrameObject * res = frame -> frame_obj ;
379+ PyFrameObject * res = frame -> frame_obj ;
294380 if (res != NULL ) {
295381 return res ;
296382 }
@@ -309,7 +395,7 @@ _PyFrame_ClearLocals(_PyInterpreterFrame *frame);
309395 * take should be set to 1 for heap allocated
310396 * frames like the ones in generators and coroutines.
311397 */
312- void
398+ PyAPI_FUNC ( void )
313399_PyFrame_ClearExceptCode (_PyInterpreterFrame * frame );
314400
315401int
@@ -358,7 +444,7 @@ _PyFrame_PushUnchecked(PyThreadState *tstate, _PyStackRef func, int null_locals_
358444/* Pushes a trampoline frame without checking for space.
359445 * Must be guarded by _PyThreadState_HasStackSpace() */
360446static inline _PyInterpreterFrame *
361- _PyFrame_PushTrampolineUnchecked (PyThreadState * tstate , PyCodeObject * code , int stackdepth , _PyInterpreterFrame * previous )
447+ _PyFrame_PushTrampolineUnchecked (PyThreadState * tstate , PyCodeObject * code , int stackdepth , _PyInterpreterFrame * previous )
362448{
363449 CALL_STAT_INC (frames_pushed );
364450 _PyInterpreterFrame * frame = (_PyInterpreterFrame * )tstate -> datastack_top ;
0 commit comments