@@ -170,15 +170,22 @@ static pm_result match_binding(zval *zv, zend_ast *pattern)
170170 return PM_MISMATCH ;
171171 }
172172
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 ;
181183 }
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+
182189 return PM_MATCH ;
183190}
184191
@@ -246,7 +253,6 @@ pm_result match_class_const(zval *zv, zend_ast *pattern)
246253pm_result zend_pattern_match_ex (zval * zv , zend_ast * pattern )
247254{
248255 ZVAL_DEREF (zv );
249- // FIXME: Do we need DEINDIRECT too?
250256
251257 switch (pattern -> kind ) {
252258 case ZEND_AST_TYPE_PATTERN :
@@ -283,7 +289,80 @@ pm_result zend_pattern_match_ex(zval *zv, zend_ast *pattern)
283289 }
284290}
285291
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+
286355bool zend_pattern_match (zval * zv , zend_ast * pattern )
287356{
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+ }
289368}
0 commit comments