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,112 +60,117 @@ 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_init );
105
100
zend_llist_destroy (& zend_observer_fiber_switch );
106
101
zend_llist_destroy (& zend_observer_fiber_destroy );
107
102
}
108
103
109
- static void zend_observer_fcall_install (zend_execute_data * execute_data ) {
110
- zend_llist_element * element ;
104
+ static void zend_observer_fcall_install (zend_execute_data * execute_data )
105
+ {
111
106
zend_llist * list = & zend_observers_fcall_list ;
112
107
zend_function * function = execute_data -> func ;
113
108
zend_op_array * op_array = & function -> op_array ;
114
109
115
- if (fcall_handlers_arena == NULL ) {
116
- return ;
117
- }
118
-
119
110
ZEND_ASSERT (function -> type != ZEND_INTERNAL_FUNCTION );
120
111
121
- zend_llist handlers_list ;
122
- zend_llist_init (& handlers_list , sizeof (zend_observer_fcall_handlers ), NULL , 0 );
123
- for (element = list -> head ; element ; element = element -> next ) {
112
+ ZEND_ASSERT (RUN_TIME_CACHE (op_array ));
113
+ zend_observer_fcall_begin_handler * begin_handlers = (zend_observer_fcall_begin_handler * )& ZEND_OBSERVER_DATA (op_array );
114
+ zend_observer_fcall_end_handler * end_handlers = (zend_observer_fcall_end_handler * )begin_handlers + list -> count , * end_handlers_start = end_handlers ;
115
+
116
+ * begin_handlers = ZEND_OBSERVER_NOT_OBSERVED ;
117
+ * end_handlers = ZEND_OBSERVER_NOT_OBSERVED ;
118
+
119
+ for (zend_llist_element * element = list -> head ; element ; element = element -> next ) {
124
120
zend_observer_fcall_init init ;
125
121
memcpy (& init , element -> data , sizeof init );
126
122
zend_observer_fcall_handlers handlers = init (execute_data );
127
- if (handlers .begin || handlers . end ) {
128
- zend_llist_add_element ( & handlers_list , & handlers ) ;
123
+ if (handlers .begin ) {
124
+ * ( begin_handlers ++ ) = handlers . begin ;
129
125
}
130
- }
131
-
132
- ZEND_ASSERT (RUN_TIME_CACHE (op_array ));
133
- void * ext ;
134
- if (handlers_list .count ) {
135
- size_t size = sizeof (zend_observer_fcall_data ) + (handlers_list .count - 1 ) * sizeof (zend_observer_fcall_handlers );
136
- zend_observer_fcall_data * fcall_data = zend_arena_alloc (& fcall_handlers_arena , size );
137
- zend_observer_fcall_handlers * handlers = fcall_data -> handlers ;
138
- for (element = handlers_list .head ; element ; element = element -> next ) {
139
- memcpy (handlers ++ , element -> data , sizeof * handlers );
126
+ if (handlers .end ) {
127
+ * (end_handlers ++ ) = handlers .end ;
140
128
}
141
- fcall_data -> end = handlers ;
142
- ext = fcall_data ;
143
- } else {
144
- ext = ZEND_OBSERVER_NOT_OBSERVED ;
145
129
}
146
-
147
- ZEND_OBSERVER_DATA (op_array ) = ext ;
148
- zend_llist_destroy (& handlers_list );
130
+
131
+ // end handlers are executed in reverse order
132
+ for (-- end_handlers ; end_handlers_start < end_handlers ; -- end_handlers , ++ end_handlers_start ) {
133
+ zend_observer_fcall_end_handler tmp = * end_handlers ;
134
+ * end_handlers = * end_handlers_start ;
135
+ * end_handlers_start = tmp ;
136
+ }
149
137
}
150
138
151
139
static void ZEND_FASTCALL _zend_observe_fcall_begin (zend_execute_data * execute_data )
152
140
{
153
- zend_op_array * op_array ;
154
- uint32_t fn_flags ;
155
- zend_observer_fcall_data * fcall_data ;
156
- zend_observer_fcall_handlers * handlers , * end ;
157
-
158
141
if (!ZEND_OBSERVER_ENABLED ) {
159
142
return ;
160
143
}
161
144
162
- op_array = & execute_data -> func -> op_array ;
163
- fn_flags = op_array -> fn_flags ;
145
+ zend_op_array * op_array = & execute_data -> func -> op_array ;
146
+ uint32_t fn_flags = op_array -> fn_flags ;
164
147
165
148
if (!ZEND_OBSERVABLE_FN (fn_flags )) {
166
149
return ;
167
150
}
168
151
169
- fcall_data = ZEND_OBSERVER_DATA (op_array );
170
- if (!fcall_data ) {
152
+ zend_observer_fcall_begin_handler * handler = ( zend_observer_fcall_begin_handler * ) & ZEND_OBSERVER_DATA (op_array );
153
+ if (!* handler ) {
171
154
zend_observer_fcall_install (execute_data );
172
- fcall_data = ZEND_OBSERVER_DATA (op_array );
173
155
}
174
156
175
- ZEND_ASSERT (fcall_data );
176
- if (fcall_data == ZEND_OBSERVER_NOT_OBSERVED ) {
177
- return ;
178
- }
157
+ zend_observer_fcall_begin_handler * possible_handlers_end = handler + zend_observers_fcall_list .count ;
179
158
180
- if (first_observed_frame == NULL ) {
181
- first_observed_frame = execute_data ;
159
+ zend_observer_fcall_end_handler * end_handler = (zend_observer_fcall_end_handler * )possible_handlers_end ;
160
+ if (* end_handler != ZEND_OBSERVER_NOT_OBSERVED ) {
161
+ if (first_observed_frame == NULL ) {
162
+ first_observed_frame = execute_data ;
163
+ }
164
+ current_observed_frame = execute_data ;
182
165
}
183
- current_observed_frame = execute_data ;
184
166
185
- end = fcall_data -> end ;
186
- for (handlers = fcall_data -> handlers ; handlers != end ; ++ handlers ) {
187
- if (handlers -> begin ) {
188
- handlers -> begin (execute_data );
189
- }
167
+ if (* handler == ZEND_OBSERVER_NOT_OBSERVED ) {
168
+ return ;
190
169
}
170
+
171
+ do {
172
+ (* handler )(execute_data );
173
+ } while (++ handler != possible_handlers_end && * handler != NULL );
191
174
}
192
175
193
176
ZEND_API void ZEND_FASTCALL zend_observer_generator_resume (zend_execute_data * execute_data )
@@ -203,43 +186,48 @@ ZEND_API void ZEND_FASTCALL zend_observer_fcall_begin(zend_execute_data *execute
203
186
}
204
187
}
205
188
206
- ZEND_API void ZEND_FASTCALL zend_observer_fcall_end (
207
- zend_execute_data * execute_data ,
208
- zval * return_value )
189
+ static inline bool zend_observer_is_skipped_frame (zend_execute_data * execute_data ) {
190
+ zend_function * func = execute_data -> func ;
191
+
192
+ if (!func || func -> type == ZEND_INTERNAL_FUNCTION || !ZEND_OBSERVABLE_FN (func -> common .fn_flags )) {
193
+ return true;
194
+ }
195
+
196
+ zend_observer_fcall_end_handler end_handler = (& ZEND_OBSERVER_DATA (& func -> op_array ))[zend_observers_fcall_list .count ];
197
+ if (end_handler == NULL || end_handler == ZEND_OBSERVER_NOT_OBSERVED ) {
198
+ return true;
199
+ }
200
+
201
+ return false;
202
+ }
203
+
204
+ ZEND_API void ZEND_FASTCALL zend_observer_fcall_end (zend_execute_data * execute_data , zval * return_value )
209
205
{
210
206
zend_function * func = execute_data -> func ;
211
- zend_observer_fcall_data * fcall_data ;
212
- zend_observer_fcall_handlers * handlers , * end ;
213
207
214
208
if (!ZEND_OBSERVER_ENABLED
215
209
|| !ZEND_OBSERVABLE_FN (func -> common .fn_flags )) {
216
210
return ;
217
211
}
218
212
219
- fcall_data = (zend_observer_fcall_data * ) ZEND_OBSERVER_DATA (& func -> op_array );
213
+ zend_observer_fcall_end_handler * handler = (zend_observer_fcall_end_handler * ) & ZEND_OBSERVER_DATA (& func -> op_array ) + zend_observers_fcall_list . count ;
220
214
// TODO: Fix exceptions from generators
221
215
// ZEND_ASSERT(fcall_data);
222
- if (!fcall_data || fcall_data == ZEND_OBSERVER_NOT_OBSERVED ) {
216
+ if (!* handler || * handler == ZEND_OBSERVER_NOT_OBSERVED ) {
223
217
return ;
224
218
}
225
219
226
- handlers = fcall_data -> end ;
227
- end = fcall_data -> handlers ;
228
- while (handlers -- != end ) {
229
- if (handlers -> end ) {
230
- handlers -> end (execute_data , return_value );
231
- }
232
- }
220
+ zend_observer_fcall_end_handler * possible_handlers_end = handler + zend_observers_fcall_list .count ;
221
+ do {
222
+ (* handler )(execute_data , return_value );
223
+ } while (++ handler != possible_handlers_end && * handler != NULL );
233
224
234
225
if (first_observed_frame == execute_data ) {
235
226
first_observed_frame = NULL ;
236
227
current_observed_frame = NULL ;
237
228
} else {
238
229
zend_execute_data * ex = execute_data -> prev_execute_data ;
239
- while (ex && (!ex -> func || ex -> func -> type == ZEND_INTERNAL_FUNCTION
240
- || !ZEND_OBSERVABLE_FN (ex -> func -> common .fn_flags )
241
- || !ZEND_OBSERVER_DATA (& ex -> func -> op_array )
242
- || ZEND_OBSERVER_DATA (& ex -> func -> op_array ) == ZEND_OBSERVER_NOT_OBSERVED )) {
230
+ while (ex && zend_observer_is_skipped_frame (ex )) {
243
231
ex = ex -> prev_execute_data ;
244
232
}
245
233
current_observed_frame = ex ;
@@ -255,7 +243,6 @@ ZEND_API void zend_observer_fcall_end_all(void)
255
243
}
256
244
ex = ex -> prev_execute_data ;
257
245
}
258
- current_observed_frame = NULL ;
259
246
}
260
247
261
248
ZEND_API void zend_observer_error_register (zend_observer_error_cb cb )
@@ -265,11 +252,8 @@ ZEND_API void zend_observer_error_register(zend_observer_error_cb cb)
265
252
266
253
void zend_observer_error_notify (int type , zend_string * error_filename , uint32_t error_lineno , zend_string * message )
267
254
{
268
- zend_llist_element * element ;
269
- zend_observer_error_cb callback ;
270
-
271
- for (element = zend_observer_error_callbacks .head ; element ; element = element -> next ) {
272
- callback = * (zend_observer_error_cb * ) (element -> data );
255
+ for (zend_llist_element * element = zend_observer_error_callbacks .head ; element ; element = element -> next ) {
256
+ zend_observer_error_cb callback = * (zend_observer_error_cb * ) (element -> data );
273
257
callback (type , error_filename , error_lineno , message );
274
258
}
275
259
}
0 commit comments