@@ -637,22 +637,17 @@ static zend_result zend_generator_get_next_delegated_value(zend_generator *gener
637637 if (iter -> index ++ > 0 ) {
638638 iter -> funcs -> move_forward (iter );
639639 if (UNEXPECTED (EG (exception ) != NULL )) {
640- goto exception ;
640+ goto failure ;
641641 }
642642 }
643643
644644 if (iter -> funcs -> valid (iter ) == FAILURE ) {
645- if (UNEXPECTED (EG (exception ) != NULL )) {
646- goto exception ;
647- }
648645 /* reached end of iteration */
649646 goto failure ;
650647 }
651648
652649 value = iter -> funcs -> get_current_data (iter );
653- if (UNEXPECTED (EG (exception ) != NULL )) {
654- goto exception ;
655- } else if (UNEXPECTED (!value )) {
650+ if (UNEXPECTED (EG (exception ) != NULL ) || UNEXPECTED (!value )) {
656651 goto failure ;
657652 }
658653
@@ -664,17 +659,14 @@ static zend_result zend_generator_get_next_delegated_value(zend_generator *gener
664659 iter -> funcs -> get_current_key (iter , & generator -> key );
665660 if (UNEXPECTED (EG (exception ) != NULL )) {
666661 ZVAL_UNDEF (& generator -> key );
667- goto exception ;
662+ goto failure ;
668663 }
669664 } else {
670665 ZVAL_LONG (& generator -> key , iter -> index );
671666 }
672667 }
673668 return SUCCESS ;
674669
675- exception :
676- zend_generator_throw_exception (generator , NULL );
677-
678670failure :
679671 zval_ptr_dtor (& generator -> values );
680672 ZVAL_UNDEF (& generator -> values );
@@ -706,94 +698,97 @@ ZEND_API void zend_generator_resume(zend_generator *orig_generator) /* {{{ */
706698 /* Drop the AT_FIRST_YIELD flag */
707699 orig_generator -> flags &= ~ZEND_GENERATOR_AT_FIRST_YIELD ;
708700
701+ /* Backup executor globals */
702+ zend_execute_data * original_execute_data = EG (current_execute_data );
703+ uint32_t original_jit_trace_num = EG (jit_trace_num );
704+
705+ /* Set executor globals */
706+ EG (current_execute_data ) = generator -> execute_data ;
707+ EG (jit_trace_num ) = 0 ;
708+
709+ /* We want the backtrace to look as if the generator function was
710+ * called from whatever method we are current running (e.g. next()).
711+ * So we have to link generator call frame with caller call frame. */
712+ if (generator == orig_generator ) {
713+ generator -> execute_data -> prev_execute_data = original_execute_data ;
714+ } else {
715+ /* We need some execute_data placeholder in stacktrace to be replaced
716+ * by the real stack trace when needed */
717+ generator -> execute_data -> prev_execute_data = & orig_generator -> execute_fake ;
718+ orig_generator -> execute_fake .prev_execute_data = original_execute_data ;
719+ }
720+
721+ /* Ensure this is run after executor_data swap to have a proper stack trace */
709722 if (UNEXPECTED (!Z_ISUNDEF (generator -> values ))) {
710723 if (EXPECTED (zend_generator_get_next_delegated_value (generator ) == SUCCESS )) {
724+ /* Restore executor globals */
725+ EG (current_execute_data ) = original_execute_data ;
726+ EG (jit_trace_num ) = original_jit_trace_num ;
727+
711728 orig_generator -> flags &= ~ZEND_GENERATOR_DO_INIT ;
712729 return ;
713730 }
714731 /* If there are no more delegated values, resume the generator
715732 * after the "yield from" expression. */
716733 }
717734
718- {
719- /* Backup executor globals */
720- zend_execute_data * original_execute_data = EG (current_execute_data );
721- uint32_t original_jit_trace_num = EG (jit_trace_num );
722-
723- /* Set executor globals */
724- EG (current_execute_data ) = generator -> execute_data ;
725- EG (jit_trace_num ) = 0 ;
726-
727- /* We want the backtrace to look as if the generator function was
728- * called from whatever method we are current running (e.g. next()).
729- * So we have to link generator call frame with caller call frame. */
730- if (generator == orig_generator ) {
731- generator -> execute_data -> prev_execute_data = original_execute_data ;
732- } else {
733- /* We need some execute_data placeholder in stacktrace to be replaced
734- * by the real stack trace when needed */
735- generator -> execute_data -> prev_execute_data = & orig_generator -> execute_fake ;
736- orig_generator -> execute_fake .prev_execute_data = original_execute_data ;
737- }
735+ if (UNEXPECTED (generator -> frozen_call_stack )) {
736+ /* Restore frozen call-stack */
737+ zend_generator_restore_call_stack (generator );
738+ }
738739
739- if (UNEXPECTED (generator -> frozen_call_stack )) {
740- /* Restore frozen call-stack */
741- zend_generator_restore_call_stack (generator );
740+ /* Resume execution */
741+ generator -> flags |= ZEND_GENERATOR_CURRENTLY_RUNNING ;
742+ if (!ZEND_OBSERVER_ENABLED ) {
743+ zend_execute_ex (generator -> execute_data );
744+ } else {
745+ zend_observer_generator_resume (generator -> execute_data );
746+ zend_execute_ex (generator -> execute_data );
747+ if (generator -> execute_data ) {
748+ /* On the final return, this will be called from ZEND_GENERATOR_RETURN */
749+ zend_observer_fcall_end (generator -> execute_data , & generator -> value );
742750 }
751+ }
752+ generator -> flags &= ~ZEND_GENERATOR_CURRENTLY_RUNNING ;
743753
744- /* Resume execution */
745- generator -> flags |= ZEND_GENERATOR_CURRENTLY_RUNNING ;
746- if (!ZEND_OBSERVER_ENABLED ) {
747- zend_execute_ex (generator -> execute_data );
748- } else {
749- zend_observer_generator_resume (generator -> execute_data );
750- zend_execute_ex (generator -> execute_data );
751- if (generator -> execute_data ) {
752- /* On the final return, this will be called from ZEND_GENERATOR_RETURN */
753- zend_observer_fcall_end (generator -> execute_data , & generator -> value );
754- }
755- }
756- generator -> flags &= ~ZEND_GENERATOR_CURRENTLY_RUNNING ;
754+ generator -> frozen_call_stack = NULL ;
755+ if (EXPECTED (generator -> execute_data ) &&
756+ UNEXPECTED (generator -> execute_data -> call )) {
757+ /* Frize call-stack */
758+ generator -> frozen_call_stack = zend_generator_freeze_call_stack (generator -> execute_data );
759+ }
757760
758- generator -> frozen_call_stack = NULL ;
759- if (EXPECTED (generator -> execute_data ) &&
760- UNEXPECTED (generator -> execute_data -> call )) {
761- /* Frize call-stack */
762- generator -> frozen_call_stack = zend_generator_freeze_call_stack (generator -> execute_data );
763- }
761+ /* Restore executor globals */
762+ EG (current_execute_data ) = original_execute_data ;
763+ EG (jit_trace_num ) = original_jit_trace_num ;
764764
765- /* Restore executor globals */
766- EG (current_execute_data ) = original_execute_data ;
767- EG (jit_trace_num ) = original_jit_trace_num ;
768-
769- /* If an exception was thrown in the generator we have to internally
770- * rethrow it in the parent scope.
771- * In case we did yield from, the Exception must be rethrown into
772- * its calling frame (see above in if (check_yield_from). */
773- if (UNEXPECTED (EG (exception ) != NULL )) {
774- if (generator == orig_generator ) {
775- zend_generator_close (generator , 0 );
776- if (!EG (current_execute_data )) {
777- zend_throw_exception_internal (NULL );
778- } else if (EG (current_execute_data )-> func &&
779- ZEND_USER_CODE (EG (current_execute_data )-> func -> common .type )) {
780- zend_rethrow_exception (EG (current_execute_data ));
781- }
782- } else {
783- generator = zend_generator_get_current (orig_generator );
784- zend_generator_throw_exception (generator , NULL );
785- orig_generator -> flags &= ~ZEND_GENERATOR_DO_INIT ;
786- goto try_again ;
765+ /* If an exception was thrown in the generator we have to internally
766+ * rethrow it in the parent scope.
767+ * In case we did yield from, the Exception must be rethrown into
768+ * its calling frame (see above in if (check_yield_from). */
769+ if (UNEXPECTED (EG (exception ) != NULL )) {
770+ if (generator == orig_generator ) {
771+ zend_generator_close (generator , 0 );
772+ if (!EG (current_execute_data )) {
773+ zend_throw_exception_internal (NULL );
774+ } else if (EG (current_execute_data )-> func &&
775+ ZEND_USER_CODE (EG (current_execute_data )-> func -> common .type )) {
776+ zend_rethrow_exception (EG (current_execute_data ));
787777 }
788- }
789-
790- /* yield from was used, try another resume. */
791- if (UNEXPECTED ((generator != orig_generator && !Z_ISUNDEF (generator -> retval )) || (generator -> execute_data && (generator -> execute_data -> opline - 1 )-> opcode == ZEND_YIELD_FROM ))) {
778+ } else {
792779 generator = zend_generator_get_current (orig_generator );
780+ zend_generator_throw_exception (generator , NULL );
781+ orig_generator -> flags &= ~ZEND_GENERATOR_DO_INIT ;
793782 goto try_again ;
794783 }
795784 }
796785
786+ /* yield from was used, try another resume. */
787+ if (UNEXPECTED ((generator != orig_generator && !Z_ISUNDEF (generator -> retval )) || (generator -> execute_data && (generator -> execute_data -> opline - 1 )-> opcode == ZEND_YIELD_FROM ))) {
788+ generator = zend_generator_get_current (orig_generator );
789+ goto try_again ;
790+ }
791+
797792 orig_generator -> flags &= ~ZEND_GENERATOR_DO_INIT ;
798793}
799794/* }}} */
0 commit comments