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