@@ -78,6 +78,18 @@ ZEND_API void zend_observer_post_startup(void)
7878 ZEND_VM_SET_OPCODE_HANDLER (EG (exception_op ));
7979 ZEND_VM_SET_OPCODE_HANDLER (EG (exception_op ) + 1 );
8080 ZEND_VM_SET_OPCODE_HANDLER (EG (exception_op ) + 2 );
81+
82+ // Add an observer temporary to store previous observed frames
83+ zend_internal_function * zif ;
84+ ZEND_HASH_FOREACH_PTR (CG (function_table ), zif ) {
85+ ++ zif -> T ;
86+ } ZEND_HASH_FOREACH_END ();
87+ zend_class_entry * ce ;
88+ ZEND_HASH_MAP_FOREACH_PTR (CG (class_table ), ce ) {
89+ ZEND_HASH_MAP_FOREACH_PTR (& ce -> function_table , zif ) {
90+ ++ zif -> T ;
91+ } ZEND_HASH_FOREACH_END ();
92+ } ZEND_HASH_FOREACH_END ();
8193 }
8294}
8395
@@ -187,6 +199,11 @@ ZEND_API bool zend_observer_remove_end_handler(zend_function *function, zend_obs
187199 return zend_observer_remove_handler ((void * * )& ZEND_OBSERVER_DATA (function ) + registered_observers , end );
188200}
189201
202+ static inline zend_execute_data * * prev_observed_frame (zend_execute_data * execute_data ) {
203+ zend_function * func = EX (func );
204+ return (zend_execute_data * * )& Z_PTR_P (EX_VAR_NUM ((ZEND_USER_CODE (func -> type ) ? func -> op_array .last_var : ZEND_CALL_NUM_ARGS (execute_data )) + func -> common .T - 1 ));
205+ }
206+
190207static void ZEND_FASTCALL _zend_observe_fcall_begin (zend_execute_data * execute_data )
191208{
192209 if (!ZEND_OBSERVER_ENABLED ) {
@@ -208,9 +225,7 @@ static void ZEND_FASTCALL _zend_observe_fcall_begin(zend_execute_data *execute_d
208225
209226 zend_observer_fcall_end_handler * end_handler = (zend_observer_fcall_end_handler * )possible_handlers_end ;
210227 if (* end_handler != ZEND_OBSERVER_NOT_OBSERVED ) {
211- if (first_observed_frame == NULL ) {
212- first_observed_frame = execute_data ;
213- }
228+ * prev_observed_frame (execute_data ) = current_observed_frame ;
214229 current_observed_frame = execute_data ;
215230 }
216231
@@ -236,29 +251,9 @@ ZEND_API void ZEND_FASTCALL zend_observer_fcall_begin(zend_execute_data *execute
236251 }
237252}
238253
239- static inline bool zend_observer_is_skipped_frame (zend_execute_data * execute_data ) {
240- zend_function * func = execute_data -> func ;
241-
242- if (!func || !ZEND_OBSERVABLE_FN (func )) {
243- return true;
244- }
245-
246- zend_observer_fcall_end_handler end_handler = (& ZEND_OBSERVER_DATA (func ))[zend_observers_fcall_list .count ];
247- if (end_handler == NULL || end_handler == ZEND_OBSERVER_NOT_OBSERVED ) {
248- return true;
249- }
250-
251- return false;
252- }
253-
254- ZEND_API void ZEND_FASTCALL zend_observer_fcall_end (zend_execute_data * execute_data , zval * return_value )
255- {
254+ static inline void call_end_observers (zend_execute_data * execute_data , zval * return_value ) {
256255 zend_function * func = execute_data -> func ;
257256
258- if (!ZEND_OBSERVER_ENABLED || !ZEND_OBSERVABLE_FN (func )) {
259- return ;
260- }
261-
262257 zend_observer_fcall_end_handler * handler = (zend_observer_fcall_end_handler * )& ZEND_OBSERVER_DATA (func ) + zend_observers_fcall_list .count ;
263258 // TODO: Fix exceptions from generators
264259 // ZEND_ASSERT(fcall_data);
@@ -270,28 +265,27 @@ ZEND_API void ZEND_FASTCALL zend_observer_fcall_end(zend_execute_data *execute_d
270265 do {
271266 (* handler )(execute_data , return_value );
272267 } while (++ handler != possible_handlers_end && * handler != NULL );
268+ }
273269
274- if (first_observed_frame == execute_data ) {
275- first_observed_frame = NULL ;
276- current_observed_frame = NULL ;
277- } else {
278- zend_execute_data * ex = execute_data -> prev_execute_data ;
279- while (ex && zend_observer_is_skipped_frame (ex )) {
280- ex = ex -> prev_execute_data ;
281- }
282- current_observed_frame = ex ;
270+ ZEND_API void ZEND_FASTCALL zend_observer_fcall_end (zend_execute_data * execute_data , zval * return_value )
271+ {
272+ if (execute_data != current_observed_frame ) {
273+ return ;
283274 }
275+ call_end_observers (execute_data , return_value );
276+ current_observed_frame = * prev_observed_frame (execute_data );
284277}
285278
286279ZEND_API void zend_observer_fcall_end_all (void )
287280{
288- zend_execute_data * ex = current_observed_frame ;
289- while ( ex ! = NULL ) {
290- if ( ex -> func ) {
291- zend_observer_fcall_end ( ex , NULL ) ;
292- }
293- ex = ex -> prev_execute_data ;
281+ zend_execute_data * execute_data = current_observed_frame , * original_execute_data = EG ( current_execute_data ) ;
282+ current_observed_frame = NULL ;
283+ while ( execute_data ) {
284+ EG ( current_execute_data ) = execute_data ;
285+ call_end_observers ( execute_data , NULL );
286+ execute_data = * prev_observed_frame ( execute_data ) ;
294287 }
288+ EG (current_execute_data ) = original_execute_data ;
295289}
296290
297291ZEND_API void zend_observer_error_register (zend_observer_error_cb cb )
0 commit comments