31
31
#define ZEND_OBSERVABLE_FN (fn_flags ) \
32
32
(!(fn_flags & ZEND_ACC_CALL_VIA_TRAMPOLINE))
33
33
34
- typedef struct _zend_observer_fcall_data {
35
- // points after the last handler
36
- zend_observer_fcall_handlers * end ;
37
- // a variadic array using "struct hack"
38
- zend_observer_fcall_handlers handlers [1 ];
39
- } zend_observer_fcall_data ;
40
-
41
34
zend_llist zend_observers_fcall_list ;
42
35
zend_llist zend_observer_error_callbacks ;
43
36
zend_llist zend_observer_fiber_init ;
@@ -46,33 +39,18 @@ zend_llist zend_observer_fiber_destroy;
46
39
47
40
int zend_observer_fcall_op_array_extension ;
48
41
49
- ZEND_TLS zend_arena * fcall_handlers_arena ;
50
42
ZEND_TLS zend_execute_data * first_observed_frame ;
51
43
ZEND_TLS zend_execute_data * current_observed_frame ;
52
44
53
45
// Call during minit/startup ONLY
54
- ZEND_API void zend_observer_fcall_register (zend_observer_fcall_init init ) {
55
- if (!ZEND_OBSERVER_ENABLED ) {
56
- /* We don't want to get an extension handle unless an ext installs an observer */
57
- zend_observer_fcall_op_array_extension =
58
- zend_get_op_array_extension_handle ("Zend Observer" );
59
-
60
- /* ZEND_CALL_TRAMPOLINE has SPEC(OBSERVER) but zend_init_call_trampoline_op()
61
- * is called before any extensions have registered as an observer. So we
62
- * adjust the offset to the observed handler when we know we need to observe. */
63
- ZEND_VM_SET_OPCODE_HANDLER (& EG (call_trampoline_op ));
64
-
65
- /* ZEND_HANDLE_EXCEPTION also has SPEC(OBSERVER) and no observer extensions
66
- * exist when zend_init_exception_op() is called. */
67
- ZEND_VM_SET_OPCODE_HANDLER (EG (exception_op ));
68
- ZEND_VM_SET_OPCODE_HANDLER (EG (exception_op )+ 1 );
69
- ZEND_VM_SET_OPCODE_HANDLER (EG (exception_op )+ 2 );
70
- }
46
+ ZEND_API void zend_observer_fcall_register (zend_observer_fcall_init init )
47
+ {
71
48
zend_llist_add_element (& zend_observers_fcall_list , & init );
72
49
}
73
50
74
51
// Called by engine before MINITs
75
- ZEND_API void zend_observer_startup (void ) {
52
+ ZEND_API void zend_observer_startup (void )
53
+ {
76
54
zend_llist_init (& zend_observers_fcall_list , sizeof (zend_observer_fcall_init ), NULL , 1 );
77
55
zend_llist_init (& zend_observer_error_callbacks , sizeof (zend_observer_error_cb ), NULL , 1 );
78
56
zend_llist_init (& zend_observer_fiber_init , sizeof (zend_observer_fiber_init_handler ), NULL , 1 );
@@ -82,110 +60,115 @@ ZEND_API void zend_observer_startup(void) {
82
60
zend_observer_fcall_op_array_extension = -1 ;
83
61
}
84
62
85
- ZEND_API void zend_observer_activate (void ) {
86
- if (ZEND_OBSERVER_ENABLED ) {
87
- fcall_handlers_arena = zend_arena_create (4096 );
88
- } else {
89
- fcall_handlers_arena = NULL ;
63
+ ZEND_API void zend_observer_post_startup (void )
64
+ {
65
+ if (zend_observers_fcall_list .count ) {
66
+ /* We don't want to get an extension handle unless an ext installs an observer
67
+ * Allocate each a begin and an end pointer */
68
+ zend_observer_fcall_op_array_extension =
69
+ zend_get_op_array_extension_handles ("Zend Observer" , (int ) zend_observers_fcall_list .count * 2 );
70
+
71
+ /* ZEND_CALL_TRAMPOLINE has SPEC(OBSERVER) but zend_init_call_trampoline_op()
72
+ * is called before any extensions have registered as an observer. So we
73
+ * adjust the offset to the observed handler when we know we need to observe. */
74
+ ZEND_VM_SET_OPCODE_HANDLER (& EG (call_trampoline_op ));
75
+
76
+ /* ZEND_HANDLE_EXCEPTION also has SPEC(OBSERVER) and no observer extensions
77
+ * exist when zend_init_exception_op() is called. */
78
+ ZEND_VM_SET_OPCODE_HANDLER (EG (exception_op ));
79
+ ZEND_VM_SET_OPCODE_HANDLER (EG (exception_op ) + 1 );
80
+ ZEND_VM_SET_OPCODE_HANDLER (EG (exception_op ) + 2 );
90
81
}
82
+ }
83
+
84
+ ZEND_API void zend_observer_activate (void )
85
+ {
91
86
first_observed_frame = NULL ;
92
87
current_observed_frame = NULL ;
93
88
}
94
89
95
- ZEND_API void zend_observer_deactivate (void ) {
96
- if (fcall_handlers_arena ) {
97
- zend_arena_destroy (fcall_handlers_arena );
98
- }
90
+ ZEND_API void zend_observer_deactivate (void )
91
+ {
92
+ // now empty and unused, but kept for ABI compatibility
99
93
}
100
94
101
- ZEND_API void zend_observer_shutdown (void ) {
95
+ ZEND_API void zend_observer_shutdown (void )
96
+ {
102
97
zend_llist_destroy (& zend_observers_fcall_list );
103
98
zend_llist_destroy (& zend_observer_error_callbacks );
104
99
zend_llist_destroy (& zend_observer_fiber_switch );
105
100
}
106
101
107
- static void zend_observer_fcall_install (zend_execute_data * execute_data ) {
108
- zend_llist_element * element ;
102
+ static void zend_observer_fcall_install (zend_execute_data * execute_data )
103
+ {
109
104
zend_llist * list = & zend_observers_fcall_list ;
110
105
zend_function * function = execute_data -> func ;
111
106
zend_op_array * op_array = & function -> op_array ;
112
107
113
- if (fcall_handlers_arena == NULL ) {
114
- return ;
115
- }
116
-
117
108
ZEND_ASSERT (function -> type != ZEND_INTERNAL_FUNCTION );
118
109
119
- zend_llist handlers_list ;
120
- zend_llist_init (& handlers_list , sizeof (zend_observer_fcall_handlers ), NULL , 0 );
121
- for (element = list -> head ; element ; element = element -> next ) {
110
+ ZEND_ASSERT (RUN_TIME_CACHE (op_array ));
111
+ zend_observer_fcall_begin_handler * begin_handlers = (zend_observer_fcall_begin_handler * )& ZEND_OBSERVER_DATA (op_array );
112
+ zend_observer_fcall_end_handler * end_handlers = (zend_observer_fcall_end_handler * )begin_handlers + list -> count , * end_handlers_start = end_handlers ;
113
+
114
+ * begin_handlers = ZEND_OBSERVER_NOT_OBSERVED ;
115
+ * end_handlers = ZEND_OBSERVER_NOT_OBSERVED ;
116
+
117
+ for (zend_llist_element * element = list -> head ; element ; element = element -> next ) {
122
118
zend_observer_fcall_init init ;
123
119
memcpy (& init , element -> data , sizeof init );
124
120
zend_observer_fcall_handlers handlers = init (execute_data );
125
- if (handlers .begin || handlers . end ) {
126
- zend_llist_add_element ( & handlers_list , & handlers ) ;
121
+ if (handlers .begin ) {
122
+ * ( begin_handlers ++ ) = handlers . begin ;
127
123
}
128
- }
129
-
130
- ZEND_ASSERT (RUN_TIME_CACHE (op_array ));
131
- void * ext ;
132
- if (handlers_list .count ) {
133
- size_t size = sizeof (zend_observer_fcall_data ) + (handlers_list .count - 1 ) * sizeof (zend_observer_fcall_handlers );
134
- zend_observer_fcall_data * fcall_data = zend_arena_alloc (& fcall_handlers_arena , size );
135
- zend_observer_fcall_handlers * handlers = fcall_data -> handlers ;
136
- for (element = handlers_list .head ; element ; element = element -> next ) {
137
- memcpy (handlers ++ , element -> data , sizeof * handlers );
124
+ if (handlers .end ) {
125
+ * (end_handlers ++ ) = handlers .end ;
138
126
}
139
- fcall_data -> end = handlers ;
140
- ext = fcall_data ;
141
- } else {
142
- ext = ZEND_OBSERVER_NOT_OBSERVED ;
143
127
}
144
-
145
- ZEND_OBSERVER_DATA (op_array ) = ext ;
146
- zend_llist_destroy (& handlers_list );
128
+
129
+ // end handlers are executed in reverse order
130
+ for (-- end_handlers ; end_handlers_start < end_handlers ; -- end_handlers , ++ end_handlers_start ) {
131
+ zend_observer_fcall_end_handler tmp = * end_handlers ;
132
+ * end_handlers = * end_handlers_start ;
133
+ * end_handlers_start = tmp ;
134
+ }
147
135
}
148
136
149
137
static void ZEND_FASTCALL _zend_observe_fcall_begin (zend_execute_data * execute_data )
150
138
{
151
- zend_op_array * op_array ;
152
- uint32_t fn_flags ;
153
- zend_observer_fcall_data * fcall_data ;
154
- zend_observer_fcall_handlers * handlers , * end ;
155
-
156
139
if (!ZEND_OBSERVER_ENABLED ) {
157
140
return ;
158
141
}
159
142
160
- op_array = & execute_data -> func -> op_array ;
161
- fn_flags = op_array -> fn_flags ;
143
+ zend_op_array * op_array = & execute_data -> func -> op_array ;
144
+ uint32_t fn_flags = op_array -> fn_flags ;
162
145
163
146
if (!ZEND_OBSERVABLE_FN (fn_flags )) {
164
147
return ;
165
148
}
166
149
167
- fcall_data = ZEND_OBSERVER_DATA (op_array );
168
- if (!fcall_data ) {
150
+ zend_observer_fcall_begin_handler * handler = ( zend_observer_fcall_begin_handler * ) & ZEND_OBSERVER_DATA (op_array );
151
+ if (!* handler ) {
169
152
zend_observer_fcall_install (execute_data );
170
- fcall_data = ZEND_OBSERVER_DATA (op_array );
171
153
}
172
154
173
- ZEND_ASSERT (fcall_data );
174
- if (fcall_data == ZEND_OBSERVER_NOT_OBSERVED ) {
175
- return ;
176
- }
155
+ zend_observer_fcall_begin_handler * possible_handlers_end = handler + zend_observers_fcall_list .count ;
177
156
178
- if (first_observed_frame == NULL ) {
179
- first_observed_frame = execute_data ;
157
+ zend_observer_fcall_end_handler * end_handler = (zend_observer_fcall_end_handler * )possible_handlers_end ;
158
+ if (* end_handler != ZEND_OBSERVER_NOT_OBSERVED ) {
159
+ if (first_observed_frame == NULL ) {
160
+ first_observed_frame = execute_data ;
161
+ }
162
+ current_observed_frame = execute_data ;
180
163
}
181
- current_observed_frame = execute_data ;
182
164
183
- end = fcall_data -> end ;
184
- for (handlers = fcall_data -> handlers ; handlers != end ; ++ handlers ) {
185
- if (handlers -> begin ) {
186
- handlers -> begin (execute_data );
187
- }
165
+ if (* handler == ZEND_OBSERVER_NOT_OBSERVED ) {
166
+ return ;
188
167
}
168
+
169
+ do {
170
+ (* handler )(execute_data );
171
+ } while (++ handler != possible_handlers_end && * handler != NULL );
189
172
}
190
173
191
174
ZEND_API void ZEND_FASTCALL zend_observer_generator_resume (zend_execute_data * execute_data )
@@ -201,43 +184,48 @@ ZEND_API void ZEND_FASTCALL zend_observer_fcall_begin(zend_execute_data *execute
201
184
}
202
185
}
203
186
204
- ZEND_API void ZEND_FASTCALL zend_observer_fcall_end (
205
- zend_execute_data * execute_data ,
206
- zval * return_value )
187
+ static inline bool zend_observer_is_skipped_frame (zend_execute_data * execute_data ) {
188
+ zend_function * func = execute_data -> func ;
189
+
190
+ if (!func || func -> type == ZEND_INTERNAL_FUNCTION || !ZEND_OBSERVABLE_FN (func -> common .fn_flags )) {
191
+ return true;
192
+ }
193
+
194
+ zend_observer_fcall_end_handler end_handler = (& ZEND_OBSERVER_DATA (& func -> op_array ))[zend_observers_fcall_list .count ];
195
+ if (end_handler == NULL || end_handler == ZEND_OBSERVER_NOT_OBSERVED ) {
196
+ return true;
197
+ }
198
+
199
+ return false;
200
+ }
201
+
202
+ ZEND_API void ZEND_FASTCALL zend_observer_fcall_end (zend_execute_data * execute_data , zval * return_value )
207
203
{
208
204
zend_function * func = execute_data -> func ;
209
- zend_observer_fcall_data * fcall_data ;
210
- zend_observer_fcall_handlers * handlers , * end ;
211
205
212
206
if (!ZEND_OBSERVER_ENABLED
213
207
|| !ZEND_OBSERVABLE_FN (func -> common .fn_flags )) {
214
208
return ;
215
209
}
216
210
217
- fcall_data = (zend_observer_fcall_data * ) ZEND_OBSERVER_DATA (& func -> op_array );
211
+ zend_observer_fcall_end_handler * handler = (zend_observer_fcall_end_handler * ) & ZEND_OBSERVER_DATA (& func -> op_array ) + zend_observers_fcall_list . count ;
218
212
// TODO: Fix exceptions from generators
219
213
// ZEND_ASSERT(fcall_data);
220
- if (!fcall_data || fcall_data == ZEND_OBSERVER_NOT_OBSERVED ) {
214
+ if (!* handler || * handler == ZEND_OBSERVER_NOT_OBSERVED ) {
221
215
return ;
222
216
}
223
217
224
- handlers = fcall_data -> end ;
225
- end = fcall_data -> handlers ;
226
- while (handlers -- != end ) {
227
- if (handlers -> end ) {
228
- handlers -> end (execute_data , return_value );
229
- }
230
- }
218
+ zend_observer_fcall_end_handler * possible_handlers_end = handler + zend_observers_fcall_list .count ;
219
+ do {
220
+ (* handler )(execute_data , return_value );
221
+ } while (++ handler != possible_handlers_end && * handler != NULL );
231
222
232
223
if (first_observed_frame == execute_data ) {
233
224
first_observed_frame = NULL ;
234
225
current_observed_frame = NULL ;
235
226
} else {
236
227
zend_execute_data * ex = execute_data -> prev_execute_data ;
237
- while (ex && (!ex -> func || ex -> func -> type == ZEND_INTERNAL_FUNCTION
238
- || !ZEND_OBSERVABLE_FN (ex -> func -> common .fn_flags )
239
- || !ZEND_OBSERVER_DATA (& ex -> func -> op_array )
240
- || ZEND_OBSERVER_DATA (& ex -> func -> op_array ) == ZEND_OBSERVER_NOT_OBSERVED )) {
228
+ while (ex && zend_observer_is_skipped_frame (ex )) {
241
229
ex = ex -> prev_execute_data ;
242
230
}
243
231
current_observed_frame = ex ;
@@ -253,7 +241,6 @@ ZEND_API void zend_observer_fcall_end_all(void)
253
241
}
254
242
ex = ex -> prev_execute_data ;
255
243
}
256
- current_observed_frame = NULL ;
257
244
}
258
245
259
246
ZEND_API void zend_observer_error_register (zend_observer_error_cb cb )
@@ -263,11 +250,8 @@ ZEND_API void zend_observer_error_register(zend_observer_error_cb cb)
263
250
264
251
void zend_observer_error_notify (int type , zend_string * error_filename , uint32_t error_lineno , zend_string * message )
265
252
{
266
- zend_llist_element * element ;
267
- zend_observer_error_cb callback ;
268
-
269
- for (element = zend_observer_error_callbacks .head ; element ; element = element -> next ) {
270
- callback = * (zend_observer_error_cb * ) (element -> data );
253
+ for (zend_llist_element * element = zend_observer_error_callbacks .head ; element ; element = element -> next ) {
254
+ zend_observer_error_cb callback = * (zend_observer_error_cb * ) (element -> data );
271
255
callback (type , error_filename , error_lineno , message );
272
256
}
273
257
}
0 commit comments