@@ -412,6 +412,42 @@ frame_stack_pop(PyFrameObject *f)
412412 Py_DECREF (v );
413413}
414414
415+ static PyFrameState
416+ _PyFrame_GetState (PyFrameObject * frame )
417+ {
418+ if (frame -> f_frame -> stacktop == 0 ) {
419+ return FRAME_CLEARED ;
420+ }
421+ switch (frame -> f_frame -> owner ) {
422+ case FRAME_OWNED_BY_GENERATOR :
423+ {
424+ PyGenObject * gen = _PyFrame_GetGenerator (frame -> f_frame );
425+ return gen -> gi_frame_state ;
426+ }
427+ case FRAME_OWNED_BY_THREAD :
428+ {
429+ if (frame -> f_frame -> f_lasti < 0 ) {
430+ return FRAME_CREATED ;
431+ }
432+ uint8_t * code = (uint8_t * )frame -> f_frame -> f_code -> co_code_adaptive ;
433+ int opcode = code [frame -> f_frame -> f_lasti * sizeof (_Py_CODEUNIT )];
434+ switch (_PyOpcode_Deopt [opcode ]) {
435+ case COPY_FREE_VARS :
436+ case MAKE_CELL :
437+ case RETURN_GENERATOR :
438+ /* Frame not fully initialized */
439+ return FRAME_CREATED ;
440+ default :
441+ return FRAME_EXECUTING ;
442+ }
443+ }
444+ case FRAME_OWNED_BY_FRAME_OBJECT :
445+ return FRAME_COMPLETED ;
446+ }
447+ Py_UNREACHABLE ();
448+ }
449+
450+
415451/* Setter for f_lineno - you can set f_lineno from within a trace function in
416452 * order to jump to a given line of code, subject to some restrictions. Most
417453 * lines are OK to jump to because they don't make any assumptions about the
@@ -440,6 +476,7 @@ frame_setlineno(PyFrameObject *f, PyObject* p_new_lineno, void *Py_UNUSED(ignore
440476 return -1 ;
441477 }
442478
479+ PyFrameState state = _PyFrame_GetState (f );
443480 /*
444481 * This code preserves the historical restrictions on
445482 * setting the line number of a frame.
@@ -448,28 +485,31 @@ frame_setlineno(PyFrameObject *f, PyObject* p_new_lineno, void *Py_UNUSED(ignore
448485 * In addition, jumps are forbidden when not tracing,
449486 * as this is a debugging feature.
450487 */
451- switch (f -> f_frame -> f_state ) {
452- case FRAME_CREATED :
488+ switch (PyThreadState_GET ()-> tracing_what ) {
489+ case PyTrace_EXCEPTION :
490+ PyErr_SetString (PyExc_ValueError ,
491+ "can only jump from a 'line' trace event" );
492+ return -1 ;
493+ case PyTrace_CALL :
453494 PyErr_Format (PyExc_ValueError ,
454495 "can't jump from the 'call' trace event of a new frame" );
455496 return -1 ;
456- case FRAME_RETURNED :
457- case FRAME_UNWINDING :
458- case FRAME_RAISED :
459- case FRAME_CLEARED :
497+ case PyTrace_LINE :
498+ break ;
499+ case PyTrace_RETURN :
500+ if (state == FRAME_SUSPENDED ) {
501+ break ;
502+ }
503+ /* fall through */
504+ default :
460505 PyErr_SetString (PyExc_ValueError ,
461506 "can only jump from a 'line' trace event" );
462507 return -1 ;
463- case FRAME_EXECUTING :
464- case FRAME_SUSPENDED :
465- /* You can only do this from within a trace function, not via
466- * _getframe or similar hackery. */
467- if (!f -> f_trace ) {
468- PyErr_Format (PyExc_ValueError ,
469- "f_lineno can only be set by a trace function" );
470- return -1 ;
471- }
472- break ;
508+ }
509+ if (!f -> f_trace ) {
510+ PyErr_Format (PyExc_ValueError ,
511+ "f_lineno can only be set by a trace function" );
512+ return -1 ;
473513 }
474514
475515 int new_lineno ;
@@ -555,8 +595,7 @@ frame_setlineno(PyFrameObject *f, PyObject* p_new_lineno, void *Py_UNUSED(ignore
555595 PyErr_SetString (PyExc_ValueError , msg );
556596 return -1 ;
557597 }
558- /* Unwind block stack. */
559- if (f -> f_frame -> f_state == FRAME_SUSPENDED ) {
598+ if (state == FRAME_SUSPENDED ) {
560599 /* Account for value popped by yield */
561600 start_stack = pop_value (start_stack );
562601 }
@@ -623,7 +662,9 @@ frame_dealloc(PyFrameObject *f)
623662{
624663 /* It is the responsibility of the owning generator/coroutine
625664 * to have cleared the generator pointer */
626- assert (!f -> f_frame -> is_generator );
665+
666+ assert (f -> f_frame -> owner != FRAME_OWNED_BY_GENERATOR ||
667+ _PyFrame_GetGenerator (f -> f_frame )-> gi_frame_state == FRAME_CLEARED );
627668
628669 if (_PyObject_GC_IS_TRACKED (f )) {
629670 _PyObject_GC_UNTRACK (f );
@@ -633,8 +674,7 @@ frame_dealloc(PyFrameObject *f)
633674 PyCodeObject * co = NULL ;
634675
635676 /* Kill all local variables including specials, if we own them */
636- if (f -> f_owns_frame ) {
637- f -> f_owns_frame = 0 ;
677+ if (f -> f_frame -> owner == FRAME_OWNED_BY_FRAME_OBJECT ) {
638678 assert (f -> f_frame == (_PyInterpreterFrame * )f -> _f_frame_data );
639679 _PyInterpreterFrame * frame = (_PyInterpreterFrame * )f -> _f_frame_data ;
640680 /* Don't clear code object until the end */
@@ -659,7 +699,7 @@ frame_traverse(PyFrameObject *f, visitproc visit, void *arg)
659699{
660700 Py_VISIT (f -> f_back );
661701 Py_VISIT (f -> f_trace );
662- if (f -> f_owns_frame == 0 ) {
702+ if (f -> f_frame -> owner != FRAME_OWNED_BY_FRAME_OBJECT ) {
663703 return 0 ;
664704 }
665705 assert (f -> f_frame -> frame_obj == NULL );
@@ -669,13 +709,6 @@ frame_traverse(PyFrameObject *f, visitproc visit, void *arg)
669709static int
670710frame_tp_clear (PyFrameObject * f )
671711{
672- /* Before anything else, make sure that this frame is clearly marked
673- * as being defunct! Else, e.g., a generator reachable from this
674- * frame may also point to this frame, believe itself to still be
675- * active, and try cleaning up this frame again.
676- */
677- f -> f_frame -> f_state = FRAME_CLEARED ;
678-
679712 Py_CLEAR (f -> f_trace );
680713
681714 /* locals and stack */
@@ -691,19 +724,25 @@ frame_tp_clear(PyFrameObject *f)
691724static PyObject *
692725frame_clear (PyFrameObject * f , PyObject * Py_UNUSED (ignored ))
693726{
694- if (_PyFrame_IsExecuting (f -> f_frame )) {
695- PyErr_SetString (PyExc_RuntimeError ,
696- "cannot clear an executing frame" );
697- return NULL ;
727+ if (f -> f_frame -> owner == FRAME_OWNED_BY_GENERATOR ) {
728+ PyGenObject * gen = _PyFrame_GetGenerator (f -> f_frame );
729+ if (gen -> gi_frame_state == FRAME_EXECUTING ) {
730+ goto running ;
731+ }
732+ _PyGen_Finalize ((PyObject * )gen );
698733 }
699- if (f -> f_frame -> is_generator ) {
700- assert (!f -> f_owns_frame );
701- size_t offset_in_gen = offsetof(PyGenObject , gi_iframe );
702- PyObject * gen = (PyObject * )(((char * )f -> f_frame ) - offset_in_gen );
703- _PyGen_Finalize (gen );
734+ else if (f -> f_frame -> owner == FRAME_OWNED_BY_THREAD ) {
735+ goto running ;
736+ }
737+ else {
738+ assert (f -> f_frame -> owner == FRAME_OWNED_BY_FRAME_OBJECT );
739+ (void )frame_tp_clear (f );
704740 }
705- (void )frame_tp_clear (f );
706741 Py_RETURN_NONE ;
742+ running :
743+ PyErr_SetString (PyExc_RuntimeError ,
744+ "cannot clear an executing frame" );
745+ return NULL ;
707746}
708747
709748PyDoc_STRVAR (clear__doc__ ,
@@ -835,7 +874,7 @@ PyFrame_New(PyThreadState *tstate, PyCodeObject *code,
835874 }
836875 init_frame ((_PyInterpreterFrame * )f -> _f_frame_data , func , locals );
837876 f -> f_frame = (_PyInterpreterFrame * )f -> _f_frame_data ;
838- f -> f_owns_frame = 1 ;
877+ f -> f_frame -> owner = FRAME_OWNED_BY_FRAME_OBJECT ;
839878 Py_DECREF (func );
840879 _PyObject_GC_TRACK (f );
841880 return f ;
@@ -912,7 +951,7 @@ _PyFrame_FastToLocalsWithError(_PyInterpreterFrame *frame) {
912951
913952 PyObject * name = PyTuple_GET_ITEM (co -> co_localsplusnames , i );
914953 PyObject * value = fast [i ];
915- if (frame -> f_state != FRAME_CLEARED ) {
954+ if (frame -> stacktop ) {
916955 if (kind & CO_FAST_FREE ) {
917956 // The cell was set by COPY_FREE_VARS.
918957 assert (value != NULL && PyCell_Check (value ));
@@ -1049,7 +1088,7 @@ _PyFrame_LocalsToFast(_PyInterpreterFrame *frame, int clear)
10491088void
10501089PyFrame_LocalsToFast (PyFrameObject * f , int clear )
10511090{
1052- if (f == NULL || f -> f_frame -> f_state == FRAME_CLEARED ) {
1091+ if (f == NULL || _PyFrame_GetState ( f ) == FRAME_CLEARED ) {
10531092 return ;
10541093 }
10551094 _PyFrame_LocalsToFast (f -> f_frame , clear );
@@ -1096,3 +1135,5 @@ _PyEval_BuiltinsFromGlobals(PyThreadState *tstate, PyObject *globals)
10961135
10971136 return _PyEval_GetBuiltins (tstate );
10981137}
1138+
1139+
0 commit comments