@@ -64,6 +64,7 @@ typedef struct _zend_loop_var {
64
64
uint8_t var_type ;
65
65
uint32_t var_num ;
66
66
uint32_t try_catch_offset ;
67
+ uint32_t opcode_start ;
67
68
} zend_loop_var ;
68
69
69
70
static inline uint32_t zend_alloc_cache_slots (unsigned count ) {
@@ -720,8 +721,10 @@ static inline void zend_begin_loop(
720
721
brk_cont_element -> parent = parent ;
721
722
brk_cont_element -> kind = kind ;
722
723
724
+ uint32_t start = get_next_op_number ();
725
+ info .opcode_start = start ;
726
+
723
727
if (loop_var && (loop_var -> op_type & (IS_VAR |IS_TMP_VAR ))) {
724
- uint32_t start = get_next_op_number ();
725
728
726
729
info .opcode = free_opcode ;
727
730
info .var_type = loop_var -> op_type ;
@@ -5594,17 +5597,10 @@ static bool zend_handle_loops_and_finally_ex(zend_long depth, znode *return_valu
5594
5597
return 1 ;
5595
5598
}
5596
5599
5597
- zend_brk_cont_element * brk_ctrl_element = CG (context ).current_brk_cont != -1
5598
- ? & CG (context ).brk_cont_array [CG (context ).current_brk_cont ]
5599
- : NULL ;
5600
- if (brk_ctrl_element && brk_ctrl_element -> kind == ZEND_BRK_CONT_KIND_MATCH_EXPR ) {
5601
- zend_error_noreturn (E_COMPILE_ERROR , "Match expression whose result is used must not contain return, break, continue or goto" );
5602
- }
5600
+ uint32_t free_range_opnum = (uint32_t )-1 ;
5603
5601
5604
5602
base = zend_stack_base (& CG (loop_var_stack ));
5605
5603
for (; loop_var >= base ; loop_var -- ) {
5606
- bool decrement_depth = false;
5607
-
5608
5604
if (loop_var -> opcode == ZEND_FAST_CALL ) {
5609
5605
zend_op * opline = get_next_op ();
5610
5606
@@ -5615,40 +5611,43 @@ static bool zend_handle_loops_and_finally_ex(zend_long depth, znode *return_valu
5615
5611
SET_NODE (opline -> op2 , return_value );
5616
5612
}
5617
5613
opline -> op1 .num = loop_var -> try_catch_offset ;
5614
+ if (free_range_opnum != (uint32_t )-1 ) {
5615
+ zend_op * opline = & CG (active_op_array )-> opcodes [free_range_opnum ];
5616
+ opline -> op1 .num = loop_var -> opcode_start ;
5617
+ free_range_opnum = (uint32_t )-1 ;
5618
+ }
5618
5619
} else if (loop_var -> opcode == ZEND_DISCARD_EXCEPTION ) {
5619
5620
zend_op * opline = get_next_op ();
5620
5621
opline -> opcode = ZEND_DISCARD_EXCEPTION ;
5621
5622
opline -> op1_type = IS_TMP_VAR ;
5622
5623
opline -> op1 .var = loop_var -> var_num ;
5623
5624
} else if (loop_var -> opcode == ZEND_RETURN ) {
5624
5625
/* Stack separator */
5626
+ if (free_range_opnum != (uint32_t )-1 ) {
5627
+ zend_op * opline = & CG (active_op_array )-> opcodes [free_range_opnum ];
5628
+ opline -> op1 .num = 0 ;
5629
+ }
5625
5630
break ;
5626
- } else if (depth <= 1 ) {
5627
- return 1 ;
5628
- } else if (loop_var -> opcode == ZEND_NOP ) {
5629
- /* Loop doesn't have freeable variable */
5630
- decrement_depth = true;
5631
5631
} else {
5632
- zend_op * opline ;
5633
-
5634
- ZEND_ASSERT (loop_var -> var_type & (IS_VAR |IS_TMP_VAR ));
5635
- opline = get_next_op ();
5636
- opline -> opcode = loop_var -> opcode ;
5637
- opline -> op1_type = loop_var -> var_type ;
5638
- opline -> op1 .var = loop_var -> var_num ;
5639
- opline -> extended_value = ZEND_FREE_ON_RETURN ;
5640
- decrement_depth = true;
5641
- }
5642
- if (decrement_depth ) {
5643
- depth -- ;
5644
- if (brk_ctrl_element ) {
5645
- if (brk_ctrl_element -> parent != -1 ) {
5646
- brk_ctrl_element = & CG (context ).brk_cont_array [brk_ctrl_element -> parent ];
5647
- if (brk_ctrl_element -> kind == ZEND_BRK_CONT_KIND_MATCH_EXPR ) {
5648
- zend_error_noreturn (E_COMPILE_ERROR , "Match expression whose result is used must not contain return, break, continue or goto" );
5649
- }
5650
- } else {
5651
- brk_ctrl_element = NULL ;
5632
+ if (free_range_opnum != (uint32_t )-1 ) {
5633
+ zend_op * opline = & CG (active_op_array )-> opcodes [free_range_opnum ];
5634
+ opline -> op1 .num = loop_var -> opcode_start + 1 ;
5635
+ free_range_opnum = (uint32_t )-1 ;
5636
+ }
5637
+ /* ZEND_FREE_RANGE does not decrease depth. */
5638
+ if (loop_var -> opcode != ZEND_FREE_RANGE && -- depth == 0 ) {
5639
+ break ;
5640
+ }
5641
+ if (loop_var -> opcode != ZEND_NOP ) {
5642
+ ZEND_ASSERT (loop_var -> var_type == IS_UNUSED || (loop_var -> var_type & (IS_VAR |IS_TMP_VAR )));
5643
+ zend_op * opline = get_next_op ();
5644
+ opline -> opcode = loop_var -> opcode ;
5645
+ opline -> op1_type = loop_var -> var_type ;
5646
+ opline -> op1 .var = loop_var -> var_num ;
5647
+ opline -> extended_value = ZEND_FREE_ON_RETURN ;
5648
+ if (loop_var -> opcode == ZEND_FREE_RANGE ) {
5649
+ free_range_opnum = get_next_op_number () - 1 ;
5650
+ opline -> op2 .var = loop_var -> opcode_start ;
5652
5651
}
5653
5652
}
5654
5653
}
@@ -6446,10 +6445,20 @@ static void zend_compile_match(znode *result, zend_ast *ast)
6446
6445
zend_ast_list * arms = zend_ast_get_list (ast -> child [1 ]);
6447
6446
bool has_default_arm = 0 ;
6448
6447
uint32_t opnum_match = (uint32_t )-1 ;
6448
+ uint32_t start_opnum = get_next_op_number ();
6449
6449
6450
6450
znode expr_node ;
6451
6451
zend_compile_expr (& expr_node , expr_ast );
6452
6452
6453
+ if (result ) {
6454
+ zend_loop_var info = {0 };
6455
+ info .opcode = ZEND_FREE_RANGE ;
6456
+ info .var_type = IS_UNUSED ;
6457
+ info .var_num = (uint32_t )-1 ;
6458
+ info .opcode_start = start_opnum ;
6459
+ zend_stack_push (& CG (loop_var_stack ), & info );
6460
+ }
6461
+
6453
6462
zend_begin_loop (ZEND_FREE , & expr_node , result ? ZEND_BRK_CONT_KIND_MATCH_EXPR : ZEND_BRK_CONT_KIND_SWITCH_MATCH_STMT );
6454
6463
6455
6464
znode case_node ;
@@ -6620,6 +6629,9 @@ static void zend_compile_match(znode *result, zend_ast *ast)
6620
6629
6621
6630
zend_end_loop (get_next_op_number (), & expr_node );
6622
6631
6632
+ /* Pop ZEND_FREE_RANGE. */
6633
+ zend_stack_del_top (& CG (loop_var_stack ));
6634
+
6623
6635
if (expr_node .op_type & (IS_VAR |IS_TMP_VAR )) {
6624
6636
zend_op * opline = zend_emit_op (NULL , ZEND_FREE , & expr_node , NULL );
6625
6637
opline -> extended_value = ZEND_FREE_SWITCH ;
@@ -6662,6 +6674,7 @@ static void zend_compile_try(zend_ast *ast) /* {{{ */
6662
6674
}
6663
6675
6664
6676
try_catch_offset = zend_add_try_element (get_next_op_number ());
6677
+ uint32_t try_opnum = get_next_op_number ();
6665
6678
6666
6679
if (finally_ast ) {
6667
6680
zend_loop_var fast_call ;
@@ -6675,6 +6688,7 @@ static void zend_compile_try(zend_ast *ast) /* {{{ */
6675
6688
fast_call .var_type = IS_TMP_VAR ;
6676
6689
fast_call .var_num = CG (context ).fast_call_var ;
6677
6690
fast_call .try_catch_offset = try_catch_offset ;
6691
+ fast_call .opcode_start = try_opnum ;
6678
6692
zend_stack_push (& CG (loop_var_stack ), & fast_call );
6679
6693
}
6680
6694
0 commit comments