@@ -170,15 +170,22 @@ static pm_result match_binding(zval *zv, zend_ast *pattern)
170
170
return PM_MISMATCH ;
171
171
}
172
172
173
- // FIXME: Delay to the end of pattern matching
174
- zend_execute_data * execute_data = EG (current_execute_data );
175
- uint32_t var = (uint32_t ) pattern -> attr ;
176
- zval * cv = EX_VAR (var );
177
- zend_assign_to_variable (cv , zv , IS_CV , EX_USES_STRICT_TYPES ());
178
- /* Destructor might throw */
179
- if (EG (exception )) {
180
- return PM_ERROR ;
173
+ zend_pm_context * context = EG (pm_context );
174
+ zend_pm_bindings * bindings = context -> bindings ;
175
+ if (!bindings ) {
176
+ bindings = & context -> bindings_spare ;
177
+ context -> bindings = bindings ;
178
+ } else if (bindings -> num_used == ZEND_PM_BINDINGS_SLOTS ) {
179
+ zend_pm_bindings * new_bindings = emalloc (sizeof (zend_pm_bindings ));
180
+ new_bindings -> next = bindings ;
181
+ bindings = new_bindings ;
182
+ context -> bindings = bindings ;
181
183
}
184
+
185
+ zend_pm_binding * binding = & bindings -> list [bindings -> num_used ++ ];
186
+ binding -> var = (uint32_t ) pattern -> attr ;
187
+ ZVAL_COPY (& binding -> value , zv );
188
+
182
189
return PM_MATCH ;
183
190
}
184
191
@@ -246,7 +253,6 @@ pm_result match_class_const(zval *zv, zend_ast *pattern)
246
253
pm_result zend_pattern_match_ex (zval * zv , zend_ast * pattern )
247
254
{
248
255
ZVAL_DEREF (zv );
249
- // FIXME: Do we need DEINDIRECT too?
250
256
251
257
switch (pattern -> kind ) {
252
258
case ZEND_AST_TYPE_PATTERN :
@@ -283,7 +289,80 @@ pm_result zend_pattern_match_ex(zval *zv, zend_ast *pattern)
283
289
}
284
290
}
285
291
292
+ static void create_context (void )
293
+ {
294
+ if (!EG (pm_context )) {
295
+ EG (pm_context ) = & EG (pm_context_spare );
296
+ } else {
297
+ zend_pm_context * prev = EG (pm_context );
298
+ EG (pm_context ) = emalloc (sizeof (zend_pm_context ));
299
+ EG (pm_context )-> prev = prev ;
300
+ }
301
+ }
302
+
303
+ static void pm_context_free (bool free_values )
304
+ {
305
+ zend_pm_context * context = EG (pm_context );
306
+ zend_pm_bindings * bindings = context -> bindings ;
307
+
308
+ EG (pm_context ) = context -> prev ;
309
+
310
+ while (bindings ) {
311
+ if (free_values ) {
312
+ for (uint8_t i = 0 ; i < bindings -> num_used ; i ++ ) {
313
+ zval_ptr_dtor (& bindings -> list [i ].value );
314
+ }
315
+ }
316
+ zend_pm_bindings * next = bindings -> next ;
317
+ if (bindings != & context -> bindings_spare ) {
318
+ efree (bindings );
319
+ }
320
+ bindings = bindings -> next ;
321
+ bindings = next ;
322
+ }
323
+
324
+ context -> bindings = NULL ;
325
+ memset (& context -> bindings_spare , 0 , sizeof (context -> bindings_spare ));
326
+
327
+ if (context != & EG (pm_context_spare )) {
328
+ efree (context );
329
+ } else {
330
+ memset (context , 0 , sizeof (zend_pm_context ));
331
+ }
332
+ }
333
+
334
+ static void bind_variables (void )
335
+ {
336
+ zend_pm_context * context = EG (pm_context );
337
+ zend_pm_bindings * bindings = context -> bindings ;
338
+ zend_execute_data * execute_data = EG (current_execute_data );
339
+ while (bindings ) {
340
+ for (uint32_t i = 0 ; i < bindings -> num_used ; i ++ ) {
341
+ zend_pm_binding * binding = & bindings -> list [i ];
342
+ zend_assign_to_variable (EX_VAR (binding -> var ), & binding -> value , IS_CV , EX_USES_STRICT_TYPES ());
343
+ }
344
+ bindings = bindings -> next ;
345
+ }
346
+ }
347
+
348
+ void zend_pm_contexts_free (void )
349
+ {
350
+ while (EG (pm_context )) {
351
+ pm_context_free (false);
352
+ }
353
+ }
354
+
286
355
bool zend_pattern_match (zval * zv , zend_ast * pattern )
287
356
{
288
- return zend_pattern_match_ex (zv , pattern ) == PM_MATCH ;
357
+ // FIXME: Only create context when necessary
358
+ create_context ();
359
+ pm_result result = zend_pattern_match_ex (zv , pattern );
360
+ if (result == PM_MATCH ) {
361
+ bind_variables ();
362
+ pm_context_free (true);
363
+ return true;
364
+ } else {
365
+ pm_context_free (true);
366
+ return false;
367
+ }
289
368
}
0 commit comments