@@ -655,22 +655,17 @@ static zend_result zend_generator_get_next_delegated_value(zend_generator *gener
655655 if (iter -> index ++ > 0 ) {
656656 iter -> funcs -> move_forward (iter );
657657 if (UNEXPECTED (EG (exception ) != NULL )) {
658- goto exception ;
658+ goto failure ;
659659 }
660660 }
661661
662662 if (iter -> funcs -> valid (iter ) == FAILURE ) {
663- if (UNEXPECTED (EG (exception ) != NULL )) {
664- goto exception ;
665- }
666663 /* reached end of iteration */
667664 goto failure ;
668665 }
669666
670667 value = iter -> funcs -> get_current_data (iter );
671- if (UNEXPECTED (EG (exception ) != NULL )) {
672- goto exception ;
673- } else if (UNEXPECTED (!value )) {
668+ if (UNEXPECTED (EG (exception ) != NULL ) || UNEXPECTED (!value )) {
674669 goto failure ;
675670 }
676671
@@ -682,17 +677,14 @@ static zend_result zend_generator_get_next_delegated_value(zend_generator *gener
682677 iter -> funcs -> get_current_key (iter , & generator -> key );
683678 if (UNEXPECTED (EG (exception ) != NULL )) {
684679 ZVAL_UNDEF (& generator -> key );
685- goto exception ;
680+ goto failure ;
686681 }
687682 } else {
688683 ZVAL_LONG (& generator -> key , iter -> index );
689684 }
690685 }
691686 return SUCCESS ;
692687
693- exception :
694- zend_generator_throw_exception (generator , NULL );
695-
696688failure :
697689 zval_ptr_dtor (& generator -> values );
698690 ZVAL_UNDEF (& generator -> values );
@@ -724,94 +716,97 @@ ZEND_API void zend_generator_resume(zend_generator *orig_generator) /* {{{ */
724716 /* Drop the AT_FIRST_YIELD flag */
725717 orig_generator -> flags &= ~ZEND_GENERATOR_AT_FIRST_YIELD ;
726718
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+ }
738+
739+ /* Ensure this is run after executor_data swap to have a proper stack trace */
727740 if (UNEXPECTED (!Z_ISUNDEF (generator -> values ))) {
728741 if (EXPECTED (zend_generator_get_next_delegated_value (generator ) == SUCCESS )) {
742+ /* Restore executor globals */
743+ EG (current_execute_data ) = original_execute_data ;
744+ EG (jit_trace_num ) = original_jit_trace_num ;
745+
729746 orig_generator -> flags &= ~ZEND_GENERATOR_DO_INIT ;
730747 return ;
731748 }
732749 /* If there are no more delegated values, resume the generator
733750 * after the "yield from" expression. */
734751 }
735752
736- {
737- /* Backup executor globals */
738- zend_execute_data * original_execute_data = EG (current_execute_data );
739- uint32_t original_jit_trace_num = EG (jit_trace_num );
740-
741- /* Set executor globals */
742- EG (current_execute_data ) = generator -> execute_data ;
743- EG (jit_trace_num ) = 0 ;
744-
745- /* We want the backtrace to look as if the generator function was
746- * called from whatever method we are current running (e.g. next()).
747- * So we have to link generator call frame with caller call frame. */
748- if (generator == orig_generator ) {
749- generator -> execute_data -> prev_execute_data = original_execute_data ;
750- } else {
751- /* We need some execute_data placeholder in stacktrace to be replaced
752- * by the real stack trace when needed */
753- generator -> execute_data -> prev_execute_data = & orig_generator -> execute_fake ;
754- orig_generator -> execute_fake .prev_execute_data = original_execute_data ;
755- }
753+ if (UNEXPECTED (generator -> frozen_call_stack )) {
754+ /* Restore frozen call-stack */
755+ zend_generator_restore_call_stack (generator );
756+ }
756757
757- if (UNEXPECTED (generator -> frozen_call_stack )) {
758- /* Restore frozen call-stack */
759- zend_generator_restore_call_stack (generator );
758+ /* Resume execution */
759+ generator -> flags |= ZEND_GENERATOR_CURRENTLY_RUNNING ;
760+ if (!ZEND_OBSERVER_ENABLED ) {
761+ zend_execute_ex (generator -> execute_data );
762+ } else {
763+ zend_observer_generator_resume (generator -> execute_data );
764+ zend_execute_ex (generator -> execute_data );
765+ if (generator -> execute_data ) {
766+ /* On the final return, this will be called from ZEND_GENERATOR_RETURN */
767+ zend_observer_fcall_end (generator -> execute_data , & generator -> value );
760768 }
769+ }
770+ generator -> flags &= ~ZEND_GENERATOR_CURRENTLY_RUNNING ;
761771
762- /* Resume execution */
763- generator -> flags |= ZEND_GENERATOR_CURRENTLY_RUNNING ;
764- if (!ZEND_OBSERVER_ENABLED ) {
765- zend_execute_ex (generator -> execute_data );
766- } else {
767- zend_observer_generator_resume (generator -> execute_data );
768- zend_execute_ex (generator -> execute_data );
769- if (generator -> execute_data ) {
770- /* On the final return, this will be called from ZEND_GENERATOR_RETURN */
771- zend_observer_fcall_end (generator -> execute_data , & generator -> value );
772- }
773- }
774- generator -> flags &= ~ZEND_GENERATOR_CURRENTLY_RUNNING ;
772+ generator -> frozen_call_stack = NULL ;
773+ if (EXPECTED (generator -> execute_data ) &&
774+ UNEXPECTED (generator -> execute_data -> call )) {
775+ /* Frize call-stack */
776+ generator -> frozen_call_stack = zend_generator_freeze_call_stack (generator -> execute_data );
777+ }
775778
776- generator -> frozen_call_stack = NULL ;
777- if (EXPECTED (generator -> execute_data ) &&
778- UNEXPECTED (generator -> execute_data -> call )) {
779- /* Frize call-stack */
780- generator -> frozen_call_stack = zend_generator_freeze_call_stack (generator -> execute_data );
781- }
779+ /* Restore executor globals */
780+ EG (current_execute_data ) = original_execute_data ;
781+ EG (jit_trace_num ) = original_jit_trace_num ;
782782
783- /* Restore executor globals */
784- EG (current_execute_data ) = original_execute_data ;
785- EG (jit_trace_num ) = original_jit_trace_num ;
786-
787- /* If an exception was thrown in the generator we have to internally
788- * rethrow it in the parent scope.
789- * In case we did yield from, the Exception must be rethrown into
790- * its calling frame (see above in if (check_yield_from). */
791- if (UNEXPECTED (EG (exception ) != NULL )) {
792- if (generator == orig_generator ) {
793- zend_generator_close (generator , 0 );
794- if (!EG (current_execute_data )) {
795- zend_throw_exception_internal (NULL );
796- } else if (EG (current_execute_data )-> func &&
797- ZEND_USER_CODE (EG (current_execute_data )-> func -> common .type )) {
798- zend_rethrow_exception (EG (current_execute_data ));
799- }
800- } else {
801- generator = zend_generator_get_current (orig_generator );
802- zend_generator_throw_exception (generator , NULL );
803- orig_generator -> flags &= ~ZEND_GENERATOR_DO_INIT ;
804- goto try_again ;
783+ /* If an exception was thrown in the generator we have to internally
784+ * rethrow it in the parent scope.
785+ * In case we did yield from, the Exception must be rethrown into
786+ * its calling frame (see above in if (check_yield_from). */
787+ if (UNEXPECTED (EG (exception ) != NULL )) {
788+ if (generator == orig_generator ) {
789+ zend_generator_close (generator , 0 );
790+ if (!EG (current_execute_data )) {
791+ zend_throw_exception_internal (NULL );
792+ } else if (EG (current_execute_data )-> func &&
793+ ZEND_USER_CODE (EG (current_execute_data )-> func -> common .type )) {
794+ zend_rethrow_exception (EG (current_execute_data ));
805795 }
806- }
807-
808- /* yield from was used, try another resume. */
809- if (UNEXPECTED ((generator != orig_generator && !Z_ISUNDEF (generator -> retval )) || (generator -> execute_data && (generator -> execute_data -> opline - 1 )-> opcode == ZEND_YIELD_FROM ))) {
796+ } else {
810797 generator = zend_generator_get_current (orig_generator );
798+ zend_generator_throw_exception (generator , NULL );
799+ orig_generator -> flags &= ~ZEND_GENERATOR_DO_INIT ;
811800 goto try_again ;
812801 }
813802 }
814803
804+ /* yield from was used, try another resume. */
805+ if (UNEXPECTED ((generator != orig_generator && !Z_ISUNDEF (generator -> retval )) || (generator -> execute_data && (generator -> execute_data -> opline - 1 )-> opcode == ZEND_YIELD_FROM ))) {
806+ generator = zend_generator_get_current (orig_generator );
807+ goto try_again ;
808+ }
809+
815810 orig_generator -> flags &= ~ZEND_GENERATOR_DO_INIT ;
816811}
817812/* }}} */
0 commit comments