@@ -78,6 +78,18 @@ ZEND_API void zend_observer_post_startup(void)
78
78
ZEND_VM_SET_OPCODE_HANDLER (EG (exception_op ));
79
79
ZEND_VM_SET_OPCODE_HANDLER (EG (exception_op ) + 1 );
80
80
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 ();
81
93
}
82
94
}
83
95
@@ -187,6 +199,11 @@ ZEND_API bool zend_observer_remove_end_handler(zend_function *function, zend_obs
187
199
return zend_observer_remove_handler ((void * * )& ZEND_OBSERVER_DATA (function ) + registered_observers , end );
188
200
}
189
201
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
+
190
207
static void ZEND_FASTCALL _zend_observe_fcall_begin (zend_execute_data * execute_data )
191
208
{
192
209
if (!ZEND_OBSERVER_ENABLED ) {
@@ -208,9 +225,7 @@ static void ZEND_FASTCALL _zend_observe_fcall_begin(zend_execute_data *execute_d
208
225
209
226
zend_observer_fcall_end_handler * end_handler = (zend_observer_fcall_end_handler * )possible_handlers_end ;
210
227
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 ;
214
229
current_observed_frame = execute_data ;
215
230
}
216
231
@@ -236,29 +251,9 @@ ZEND_API void ZEND_FASTCALL zend_observer_fcall_begin(zend_execute_data *execute
236
251
}
237
252
}
238
253
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 ) {
256
255
zend_function * func = execute_data -> func ;
257
256
258
- if (!ZEND_OBSERVER_ENABLED || !ZEND_OBSERVABLE_FN (func )) {
259
- return ;
260
- }
261
-
262
257
zend_observer_fcall_end_handler * handler = (zend_observer_fcall_end_handler * )& ZEND_OBSERVER_DATA (func ) + zend_observers_fcall_list .count ;
263
258
// TODO: Fix exceptions from generators
264
259
// ZEND_ASSERT(fcall_data);
@@ -270,28 +265,27 @@ ZEND_API void ZEND_FASTCALL zend_observer_fcall_end(zend_execute_data *execute_d
270
265
do {
271
266
(* handler )(execute_data , return_value );
272
267
} while (++ handler != possible_handlers_end && * handler != NULL );
268
+ }
273
269
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 ;
283
274
}
275
+ call_end_observers (execute_data , return_value );
276
+ current_observed_frame = * prev_observed_frame (execute_data );
284
277
}
285
278
286
279
ZEND_API void zend_observer_fcall_end_all (void )
287
280
{
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 ) ;
294
287
}
288
+ EG (current_execute_data ) = original_execute_data ;
295
289
}
296
290
297
291
ZEND_API void zend_observer_error_register (zend_observer_error_cb cb )
0 commit comments