23
23
#include "zend_llist.h"
24
24
#include "zend_vm.h"
25
25
26
+ #define ZEND_OBSERVER_DATA (op_array ) \
27
+ ZEND_OP_ARRAY_EXTENSION(op_array, zend_observer_fcall_op_array_extension)
28
+
29
+ #define ZEND_OBSERVER_NOT_OBSERVED ((void *) 2)
30
+
31
+ #define ZEND_OBSERVABLE_FN (fn_flags ) \
32
+ (!(fn_flags & (ZEND_ACC_CALL_VIA_TRAMPOLINE | ZEND_ACC_FAKE_CLOSURE)))
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
+
26
41
zend_llist zend_observers_fcall_list ;
27
42
zend_llist zend_observer_error_callbacks ;
28
43
29
44
int zend_observer_fcall_op_array_extension = -1 ;
30
45
31
46
ZEND_TLS zend_arena * fcall_handlers_arena = NULL ;
32
47
33
- ZEND_API extern inline void zend_observer_maybe_fcall_call_begin (
34
- zend_execute_data * execute_data );
35
- ZEND_API extern inline void zend_observer_maybe_fcall_call_end (
36
- zend_execute_data * execute_data ,
37
- zval * return_value );
38
-
39
48
// Call during minit/startup ONLY
40
49
ZEND_API void zend_observer_fcall_register (zend_observer_fcall_init init ) {
41
50
/* We don't want to get an extension handle unless an ext installs an observer */
@@ -80,7 +89,7 @@ ZEND_API void zend_observer_shutdown(void) {
80
89
zend_llist_destroy (& zend_observer_error_callbacks );
81
90
}
82
91
83
- ZEND_API void zend_observer_fcall_install (zend_function * function ) {
92
+ static void zend_observer_fcall_install (zend_function * function ) {
84
93
zend_llist_element * element ;
85
94
zend_llist * list = & zend_observers_fcall_list ;
86
95
zend_op_array * op_array = & function -> op_array ;
@@ -92,11 +101,11 @@ ZEND_API void zend_observer_fcall_install(zend_function *function) {
92
101
ZEND_ASSERT (function -> type != ZEND_INTERNAL_FUNCTION );
93
102
94
103
zend_llist handlers_list ;
95
- zend_llist_init (& handlers_list , sizeof (zend_observer_fcall ), NULL , 0 );
104
+ zend_llist_init (& handlers_list , sizeof (zend_observer_fcall_handlers ), NULL , 0 );
96
105
for (element = list -> head ; element ; element = element -> next ) {
97
106
zend_observer_fcall_init init ;
98
107
memcpy (& init , element -> data , sizeof init );
99
- zend_observer_fcall handlers = init (function );
108
+ zend_observer_fcall_handlers handlers = init (function );
100
109
if (handlers .begin || handlers .end ) {
101
110
zend_llist_add_element (& handlers_list , & handlers );
102
111
}
@@ -105,58 +114,97 @@ ZEND_API void zend_observer_fcall_install(zend_function *function) {
105
114
ZEND_ASSERT (RUN_TIME_CACHE (op_array ));
106
115
void * ext ;
107
116
if (handlers_list .count ) {
108
- size_t size = sizeof (zend_observer_fcall_cache ) + (handlers_list .count - 1 ) * sizeof (zend_observer_fcall );
109
- zend_observer_fcall_cache * cache = zend_arena_alloc (& fcall_handlers_arena , size );
110
- zend_observer_fcall * handler = cache -> handlers ;
117
+ size_t size = sizeof (zend_observer_fcall_data ) + (handlers_list .count - 1 ) * sizeof (zend_observer_fcall_handlers );
118
+ zend_observer_fcall_data * fcall_data = zend_arena_alloc (& fcall_handlers_arena , size );
119
+ zend_observer_fcall_handlers * handlers = fcall_data -> handlers ;
111
120
for (element = handlers_list .head ; element ; element = element -> next ) {
112
- memcpy (handler ++ , element -> data , sizeof * handler );
121
+ memcpy (handlers ++ , element -> data , sizeof * handlers );
113
122
}
114
- cache -> end = handler ;
115
- ext = cache ;
123
+ fcall_data -> end = handlers ;
124
+ ext = fcall_data ;
116
125
} else {
117
126
ext = ZEND_OBSERVER_NOT_OBSERVED ;
118
127
}
119
128
120
- ZEND_OBSERVER_HANDLERS (op_array ) = ext ;
129
+ ZEND_OBSERVER_DATA (op_array ) = ext ;
121
130
zend_llist_destroy (& handlers_list );
122
131
}
123
132
124
- ZEND_API void zend_observe_fcall_begin (
125
- zend_observer_fcall_cache * cache ,
126
- zend_execute_data * execute_data )
133
+ static void ZEND_FASTCALL _zend_observe_fcall_begin (zend_execute_data * execute_data )
127
134
{
128
- zend_observer_fcall * handler , * end = cache -> end ;
129
- for (handler = cache -> handlers ; handler != end ; ++ handler ) {
130
- if (handler -> begin ) {
131
- handler -> begin (execute_data );
135
+ zend_op_array * op_array ;
136
+ uint32_t fn_flags ;
137
+ zend_observer_fcall_data * fcall_data ;
138
+ zend_observer_fcall_handlers * handlers , * end ;
139
+
140
+ if (!ZEND_OBSERVER_ENABLED ) {
141
+ return ;
142
+ }
143
+
144
+ op_array = & execute_data -> func -> op_array ;
145
+ fn_flags = op_array -> fn_flags ;
146
+
147
+ if (!ZEND_OBSERVABLE_FN (fn_flags )) {
148
+ return ;
149
+ }
150
+
151
+ fcall_data = ZEND_OBSERVER_DATA (op_array );
152
+ if (!fcall_data ) {
153
+ zend_observer_fcall_install ((zend_function * )op_array );
154
+ fcall_data = ZEND_OBSERVER_DATA (op_array );
155
+ }
156
+
157
+ ZEND_ASSERT (fcall_data );
158
+ if (fcall_data == ZEND_OBSERVER_NOT_OBSERVED ) {
159
+ return ;
160
+ }
161
+
162
+ end = fcall_data -> end ;
163
+ for (handlers = fcall_data -> handlers ; handlers != end ; ++ handlers ) {
164
+ if (handlers -> begin ) {
165
+ handlers -> begin (execute_data );
132
166
}
133
167
}
134
168
}
135
169
136
- ZEND_API void zend_observer_fcall_call_end_helper (
137
- zend_execute_data * execute_data ,
138
- zval * return_value )
170
+ ZEND_API void ZEND_FASTCALL zend_observer_generator_resume (zend_execute_data * execute_data )
139
171
{
140
- zend_function * func = execute_data -> func ;
141
- ZEND_ASSUME ( ZEND_OBSERVABLE_FN ( func -> common . fn_flags ));
142
- void * observer_handlers = ZEND_OBSERVER_HANDLERS ( & func -> op_array );
143
- // TODO: Fix exceptions from generators
144
- // ZEND_ASSERT(observer_handlers);
145
- if ( observer_handlers && observer_handlers != ZEND_OBSERVER_NOT_OBSERVED ) {
146
- zend_observer_fcall_cache * cache = observer_handlers ;
147
- zend_observe_fcall_end ( cache , execute_data , return_value );
172
+ _zend_observe_fcall_begin ( execute_data ) ;
173
+ }
174
+
175
+ ZEND_API void ZEND_FASTCALL zend_observer_fcall_begin ( zend_execute_data * execute_data )
176
+ {
177
+ ZEND_ASSUME ( execute_data -> func );
178
+ if (!( execute_data -> func -> common . fn_flags & ZEND_ACC_GENERATOR )) {
179
+ _zend_observe_fcall_begin ( execute_data );
148
180
}
149
181
}
150
182
151
- ZEND_API void zend_observe_fcall_end (
152
- zend_observer_fcall_cache * cache ,
183
+ ZEND_API void ZEND_FASTCALL zend_observer_fcall_end (
153
184
zend_execute_data * execute_data ,
154
185
zval * return_value )
155
186
{
156
- zend_observer_fcall * handler = cache -> end , * end = cache -> handlers ;
157
- while (handler -- != end ) {
158
- if (handler -> end ) {
159
- handler -> end (execute_data , return_value );
187
+ zend_function * func = execute_data -> func ;
188
+ zend_observer_fcall_data * fcall_data ;
189
+ zend_observer_fcall_handlers * handlers , * end ;
190
+
191
+ if (!ZEND_OBSERVER_ENABLED
192
+ || !ZEND_OBSERVABLE_FN (func -> common .fn_flags )) {
193
+ return ;
194
+ }
195
+
196
+ fcall_data = (zend_observer_fcall_data * )ZEND_OBSERVER_DATA (& func -> op_array );
197
+ // TODO: Fix exceptions from generators
198
+ // ZEND_ASSERT(fcall_data);
199
+ if (!fcall_data || fcall_data == ZEND_OBSERVER_NOT_OBSERVED ) {
200
+ return ;
201
+ }
202
+
203
+ handlers = fcall_data -> end ;
204
+ end = fcall_data -> handlers ;
205
+ while (handlers -- != end ) {
206
+ if (handlers -> end ) {
207
+ handlers -> end (execute_data , return_value );
160
208
}
161
209
}
162
210
}
0 commit comments