@@ -6644,7 +6644,7 @@ static void zend_compile_pipe(znode *result, zend_ast *ast)
66446644typedef struct {
66456645 bool inside_or_pattern ;
66466646 uint32_t num_bindings ;
6647- uint32_t first_tmp ;
6647+ uint32_t first_binding_tmp ;
66486648 zend_stack labels ;
66496649} zend_pm_context ;
66506650
@@ -6673,21 +6673,16 @@ static uint32_t zend_pm_label_create(zend_pm_context *context)
66736673static void zend_pm_label_set_next (zend_pm_context * context , uint32_t label_offset )
66746674{
66756675 uint32_t * labels = zend_stack_base (& context -> labels );
6676- uint32_t * label = & labels [- label_offset ];
6677- * label = get_next_op_number ();
6676+ labels [- label_offset ] = get_next_op_number ();
66786677}
66796678
66806679static void zend_pm_labels_replace (zend_pm_context * context , uint32_t start_opnum )
66816680{
66826681 uint32_t * labels = zend_stack_base (& context -> labels );
6683- if (!labels ) {
6684- return ;
6685- }
6686-
6682+ uint32_t label_lower_bound = - zend_stack_count (& context -> labels );
66876683 zend_op_array * op_array = CG (active_op_array );
66886684 zend_op * opline = & op_array -> opcodes [start_opnum ];
66896685 zend_op * end_opline = & op_array -> opcodes [op_array -> last ];
6690- uint32_t label_lower_bound = - zend_stack_count (& context -> labels );
66916686
66926687 while (opline < end_opline ) {
66936688 switch (opline -> opcode ) {
@@ -6706,15 +6701,15 @@ static void zend_pm_labels_replace(zend_pm_context *context, uint32_t start_opnu
67066701 }
67076702}
67086703
6709- static void zend_compile_expr_like_pattern (zend_ast * ast , znode * expr_node , bool consume_expr , uint32_t false_opnum )
6704+ static void zend_pm_compile_expr_like (zend_ast * ast , znode * expr_node , bool consume_expr , uint32_t false_opnum )
67106705{
67116706 znode result , value ;
67126707 zend_compile_expr (& value , ast -> child [0 ]);
67136708 zend_emit_op_tmp (& result , expr_node -> op_type == IS_CV || consume_expr ? ZEND_IS_IDENTICAL : ZEND_CASE_STRICT , expr_node , & value );
67146709 zend_emit_cond_jump (ZEND_JMPZ , & result , false_opnum );
67156710}
67166711
6717- static void verify_parenthesized_compound_pattern (zend_ast * ast , zend_ast_kind kind )
6712+ static void zend_pm_verify_parenthesized_compound_pattern (zend_ast * ast , zend_ast_kind kind )
67186713{
67196714 zend_ast_list * ast_list = zend_ast_get_list (ast );
67206715
@@ -6726,14 +6721,15 @@ static void verify_parenthesized_compound_pattern(zend_ast *ast, zend_ast_kind k
67266721 }
67276722}
67286723
6729- static void zend_compile_or_pattern (zend_ast * ast , znode * expr_node , bool consume_expr , uint32_t false_opnum , zend_pm_context * context )
6724+ static void zend_pm_compile_or (zend_ast * ast , znode * expr_node , bool consume_expr , uint32_t false_opnum , zend_pm_context * context )
67306725{
6731- verify_parenthesized_compound_pattern (ast , ZEND_AST_AND_PATTERN );
6726+ zend_pm_verify_parenthesized_compound_pattern (ast , ZEND_AST_AND_PATTERN );
67326727
67336728 context -> inside_or_pattern = true;
67346729
67356730 zend_ast_list * ast_list = zend_ast_get_list (ast );
67366731 uint32_t true_label = zend_pm_label_create (context );
6732+ uint32_t false_label = consume_expr ? zend_pm_label_create (context ) : false_opnum ;
67376733 uint32_t next_label = 0 ;
67386734
67396735 for (uint32_t i = 0 ; i < ast_list -> children - 1 ; i ++ ) {
@@ -6746,13 +6742,9 @@ static void zend_compile_or_pattern(zend_ast *ast, znode *expr_node, bool consum
67466742 }
67476743 zend_pm_label_set_next (context , next_label );
67486744
6749- if (!consume_expr ) {
6750- zend_compile_pattern (ast_list -> child [ast_list -> children - 1 ], expr_node , false, false_opnum , context );
6751- zend_pm_label_set_next (context , true_label );
6752- } else {
6753- uint32_t false_label = zend_pm_label_create (context );
6754- zend_compile_pattern (ast_list -> child [ast_list -> children - 1 ], expr_node , false, false_label , context );
6745+ zend_compile_pattern (ast_list -> child [ast_list -> children - 1 ], expr_node , false, false_label , context );
67556746
6747+ if (consume_expr ) {
67566748 zend_pm_label_set_next (context , true_label );
67576749 zend_emit_op (NULL , ZEND_FREE , expr_node , NULL );
67586750 uint32_t end_label = zend_emit_jump (0 );
@@ -6767,9 +6759,9 @@ static void zend_compile_or_pattern(zend_ast *ast, znode *expr_node, bool consum
67676759 context -> inside_or_pattern = false;
67686760}
67696761
6770- static void zend_compile_and_pattern (zend_ast * ast , znode * expr_node , bool consume_expr , uint32_t false_opnum , zend_pm_context * context )
6762+ static void zend_pm_compile_and (zend_ast * ast , znode * expr_node , bool consume_expr , uint32_t false_opnum , zend_pm_context * context )
67716763{
6772- verify_parenthesized_compound_pattern (ast , ZEND_AST_OR_PATTERN );
6764+ zend_pm_verify_parenthesized_compound_pattern (ast , ZEND_AST_OR_PATTERN );
67736765
67746766 zend_ast_list * ast_list = zend_ast_get_list (ast );
67756767 uint32_t false_label = consume_expr ? zend_pm_label_create (context ) : false_opnum ;
@@ -6787,12 +6779,10 @@ static void zend_compile_and_pattern(zend_ast *ast, znode *expr_node, bool consu
67876779 zend_emit_jump (false_opnum );
67886780
67896781 zend_update_jump_target_to_next (jmp_end );
6790- } else {
6791- zend_pm_label_set_next (context , false_label );
67926782 }
67936783}
67946784
6795- static void zend_compile_type_pattern (zend_ast * ast , znode * expr_node , bool consume_expr , uint32_t false_opnum )
6785+ static void zend_pm_compile_type (zend_ast * ast , znode * expr_node , bool consume_expr , uint32_t false_opnum )
67966786{
67976787 zend_ast * type_ast = ast -> child [0 ];
67986788 bool nullable = type_ast -> attr & ZEND_TYPE_NULLABLE ;
@@ -6812,66 +6802,61 @@ static void zend_compile_type_pattern(zend_ast *ast, znode *expr_node, bool cons
68126802
68136803 znode result ;
68146804 zend_emit_op (& result , ZEND_HAS_TYPE , expr_node , & type_node );
6815- if (consume_expr && ( expr_node -> op_type & ( IS_VAR | IS_TMP_VAR )) ) {
6805+ if (consume_expr ) {
68166806 zend_emit_op (NULL , ZEND_FREE , expr_node , NULL );
68176807 }
68186808 zend_emit_cond_jump (ZEND_JMPZ , & result , false_opnum );
68196809}
68206810
6821- static void zend_compile_binding_pattern (zend_ast * ast , znode * expr_node , bool consume_expr , uint32_t false_opnum , zend_pm_context * context )
6811+ static void zend_pm_copy_tmp (znode * dest , znode * src , bool consume )
6812+ {
6813+ if (!consume && (src -> op_type & (IS_VAR |IS_TMP_VAR ))) {
6814+ zend_emit_op (dest , ZEND_COPY_TMP , src , NULL );
6815+ } else {
6816+ * dest = * src ;
6817+ }
6818+ }
6819+
6820+ static void zend_pm_compile_binding (zend_ast * ast , znode * expr_node , bool consume_expr , uint32_t false_opnum , zend_pm_context * context )
68226821{
68236822 if (context -> inside_or_pattern ) {
68246823 zend_error_noreturn (E_COMPILE_ERROR , "Must not bind to variables inside | pattern" );
68256824 }
68266825
68276826 znode var_node ;
68286827 var_node .op_type = IS_TMP_VAR ;
6829- var_node .u .op .var = context -> first_tmp + context -> num_bindings ++ ;
6828+ var_node .u .op .var = context -> first_binding_tmp + context -> num_bindings ++ ;
68306829
68316830 znode expr_copy_node ;
6832- if (!consume_expr && (expr_node -> op_type & (IS_VAR |IS_TMP_VAR ))) {
6833- zend_emit_op (& expr_copy_node , ZEND_COPY_TMP , expr_node , NULL );
6834- } else {
6835- expr_copy_node = * expr_node ;
6836- }
6831+ zend_pm_copy_tmp (& expr_copy_node , expr_node , consume_expr );
68376832
68386833 zend_op * op = zend_emit_op_tmp (NULL , ZEND_QM_ASSIGN , & expr_copy_node , NULL );
68396834 SET_NODE (op -> result , & var_node );
68406835}
68416836
6842- static void zend_pm_copy_tmp (znode * dest , znode * src )
6843- {
6844- if (src -> op_type & (IS_VAR |IS_TMP_VAR )) {
6845- zend_emit_op (dest , ZEND_COPY_TMP , src , NULL );
6846- } else {
6847- * dest = * src ;
6848- }
6849- }
6850-
6851- static void zend_compile_container_pattern (
6837+ static void zend_pm_compile_container (
68526838 zend_ast * ast ,
68536839 znode * expr_node ,
68546840 bool consume_expr ,
68556841 uint32_t false_opnum ,
68566842 zend_pm_context * context ,
68576843 bool is_array
68586844) {
6859- // FIXME: These copies are annoying...
68606845 znode expr_copy_node ;
68616846
68626847 uint32_t false_label = consume_expr ? zend_pm_label_create (context ) : false_opnum ;
68636848 zend_ast_list * element_list = zend_ast_get_list (ast -> child [0 ]);
68646849
6865- /* Make sure the value is actually an array . */
6866- zend_pm_copy_tmp (& expr_copy_node , expr_node );
6850+ /* Make sure the value is actually of the right type . */
6851+ zend_pm_copy_tmp (& expr_copy_node , expr_node , false );
68676852 znode is_array_node ;
68686853 zend_op * is_array_op = zend_emit_op (& is_array_node , ZEND_TYPE_CHECK , & expr_copy_node , NULL );
68696854 is_array_op -> extended_value = is_array ? MAY_BE_ARRAY : MAY_BE_OBJECT ;
68706855 zend_emit_cond_jump (ZEND_JMPZ , & is_array_node , false_label );
68716856
6872- /* Make sure the array has the right size. */
68736857 if (is_array ) {
6874- zend_pm_copy_tmp (& expr_copy_node , expr_node );
6858+ /* Make sure the array has the right size. */
6859+ zend_pm_copy_tmp (& expr_copy_node , expr_node , false);
68756860 znode count_node ;
68766861 zend_emit_op (& count_node , ZEND_COUNT , & expr_copy_node , NULL );
68776862
@@ -6894,7 +6879,7 @@ static void zend_compile_container_pattern(
68946879 zend_ast * element_value_ast = element_ast -> child [1 ];
68956880
68966881 /* Fetch element. */
6897- zend_pm_copy_tmp (& expr_copy_node , expr_node );
6882+ zend_pm_copy_tmp (& expr_copy_node , expr_node , false );
68986883 znode element_value_node , element_key_node ;
68996884 element_key_node .op_type = IS_CONST ;
69006885 if (element_key_ast ) {
@@ -6908,9 +6893,6 @@ static void zend_compile_container_pattern(
69086893 zend_emit_op_tmp (& element_value_node , ZEND_FETCH_DIM_IS , & expr_copy_node , & element_key_node );
69096894 } else {
69106895 zend_op * fetch_prop_op = zend_emit_op_tmp (& element_value_node , ZEND_FETCH_OBJ_R , & expr_copy_node , & element_key_node );
6911- // FIXME: Are those necessary?
6912- convert_to_string (CT_CONSTANT (fetch_prop_op -> op2 ));
6913- zend_string_hash_val (Z_STR_P (CT_CONSTANT (fetch_prop_op -> op2 )));
69146896 fetch_prop_op -> extended_value = zend_alloc_cache_slots (3 );
69156897 }
69166898
@@ -6943,32 +6925,31 @@ static void zend_compile_pattern(zend_ast *ast, znode *expr_node, bool consume_e
69436925 }
69446926 break ;
69456927 case ZEND_AST_EXPR_LIKE_PATTERN :
6946- zend_compile_expr_like_pattern (ast , expr_node , consume_expr , false_opnum );
6928+ zend_pm_compile_expr_like (ast , expr_node , consume_expr , false_opnum );
69476929 break ;
69486930 case ZEND_AST_OR_PATTERN :
6949- zend_compile_or_pattern (ast , expr_node , consume_expr , false_opnum , context );
6931+ zend_pm_compile_or (ast , expr_node , consume_expr , false_opnum , context );
69506932 break ;
69516933 case ZEND_AST_AND_PATTERN :
6952- zend_compile_and_pattern (ast , expr_node , consume_expr , false_opnum , context );
6934+ zend_pm_compile_and (ast , expr_node , consume_expr , false_opnum , context );
69536935 break ;
69546936 case ZEND_AST_TYPE_PATTERN :
6955- zend_compile_type_pattern (ast , expr_node , consume_expr , false_opnum );
6937+ zend_pm_compile_type (ast , expr_node , consume_expr , false_opnum );
69566938 break ;
69576939 case ZEND_AST_BINDING_PATTERN :
6958- zend_compile_binding_pattern (ast , expr_node , consume_expr , false_opnum , context );
6940+ zend_pm_compile_binding (ast , expr_node , consume_expr , false_opnum , context );
69596941 break ;
69606942 case ZEND_AST_ARRAY_PATTERN :
6961- zend_compile_container_pattern (ast , expr_node , consume_expr , false_opnum , context , true);
6943+ zend_pm_compile_container (ast , expr_node , consume_expr , false_opnum , context , true);
69626944 break ;
69636945 case ZEND_AST_OBJECT_PATTERN :
6964- zend_compile_container_pattern (ast , expr_node , consume_expr , false_opnum , context , false);
6946+ zend_pm_compile_container (ast , expr_node , consume_expr , false_opnum , context , false);
69656947 break ;
6966- // ZEND_AST_RANGE_PATTERN
69676948 EMPTY_SWITCH_DEFAULT_CASE ();
69686949 }
69696950}
69706951
6971- static void pattern_matching_count_bindings (zend_ast * * ast_ptr , void * context )
6952+ static void zend_pm_count_bindings (zend_ast * * ast_ptr , void * context )
69726953{
69736954 zend_ast * ast = * ast_ptr ;
69746955 if (ast == NULL || ast -> kind == ZEND_AST_ZVAL ) {
@@ -6980,10 +6961,10 @@ static void pattern_matching_count_bindings(zend_ast **ast_ptr, void *context)
69806961 pattern_context -> num_bindings ++ ;
69816962 }
69826963
6983- zend_ast_apply (ast , pattern_matching_count_bindings , context );
6964+ zend_ast_apply (ast , zend_pm_count_bindings , context );
69846965}
69856966
6986- static void pattern_matching_emit_assigns (zend_ast * * ast_ptr , void * context )
6967+ static void zend_pm_emit_assigns (zend_ast * * ast_ptr , void * context )
69876968{
69886969 zend_ast * ast = * ast_ptr ;
69896970 if (ast == NULL || ast -> kind == ZEND_AST_ZVAL ) {
@@ -6999,20 +6980,20 @@ static void pattern_matching_emit_assigns(zend_ast **ast_ptr, void *context)
69996980
70006981 znode value_node ;
70016982 value_node .op_type = IS_TMP_VAR ;
7002- value_node .u .op .var = pattern_context -> first_tmp + pattern_context -> num_bindings ++ ;
6983+ value_node .u .op .var = pattern_context -> first_binding_tmp + pattern_context -> num_bindings ++ ;
70036984
70046985 zend_emit_op (NULL , ZEND_ASSIGN , & var_node , & value_node );
70056986 }
70066987
7007- zend_ast_apply (ast , pattern_matching_emit_assigns , context );
6988+ zend_ast_apply (ast , zend_pm_emit_assigns , context );
70086989}
70096990
70106991static void zend_emit_is (znode * result , znode * expr_node , bool consume_expr , zend_ast * pattern_ast )
70116992{
7012- // FIXME: Do we need a copy of expr_node? We may observe side-effects, e.g .
7013- // through hooks. Do we care?
7014-
7015- /* When expr is a CONST, create a copy to avoid inserting multiple literals . */
6993+ /* When expr is a CONST, create a copy to avoid inserting multiple literals .
6994+ * A cleaner solution would be to remember whether a literal has already been
6995+ * inserted. This could be stored in znode.flag and handled in SET_NODE().
6996+ * However, this field is unfortunately inconsistently initialized . */
70166997 znode expr_copy_node ;
70176998 if (expr_node -> op_type == IS_CONST ) {
70186999 zend_emit_op (& expr_copy_node , ZEND_QM_ASSIGN , expr_node , NULL );
@@ -7023,14 +7004,15 @@ static void zend_emit_is(znode *result, znode *expr_node, bool consume_expr, zen
70237004
70247005 zend_pm_context context = {0 };
70257006 zend_pm_context_init (& context );
7026- pattern_matching_count_bindings (& pattern_ast , & context );
7027- context .first_tmp = CG (active_op_array )-> T ;
7007+ zend_pm_count_bindings (& pattern_ast , & context );
7008+ context .first_binding_tmp = CG (active_op_array )-> T ;
70287009 CG (active_op_array )-> T += context .num_bindings ;
70297010
7011+ /* Initialize temporaries used for assignment */
70307012 for (uint32_t i = 0 ; i < context .num_bindings ; i ++ ) {
70317013 znode var_node ;
70327014 var_node .op_type = IS_TMP_VAR ;
7033- var_node .u .op .var = context .first_tmp + i ;
7015+ var_node .u .op .var = context .first_binding_tmp + i ;
70347016 znode null_node ;
70357017 null_node .op_type = IS_CONST ;
70367018 ZVAL_NULL (& null_node .u .constant );
@@ -7044,7 +7026,7 @@ static void zend_emit_is(znode *result, znode *expr_node, bool consume_expr, zen
70447026 zend_compile_pattern (pattern_ast , & expr_copy_node , consume_expr , false_label , & context );
70457027
70467028 context .num_bindings = 0 ;
7047- pattern_matching_emit_assigns (& pattern_ast , & context );
7029+ zend_pm_emit_assigns (& pattern_ast , & context );
70487030
70497031 znode true_node ;
70507032 true_node .op_type = IS_CONST ;
@@ -7055,15 +7037,14 @@ static void zend_emit_is(znode *result, znode *expr_node, bool consume_expr, zen
70557037 zend_op * opline_qm_assign = zend_emit_op_tmp (NULL , ZEND_QM_ASSIGN , & true_node , NULL );
70567038 SET_NODE (opline_qm_assign -> result , result );
70577039 }
7058-
70597040 uint32_t jmp_end = zend_emit_jump (0 );
70607041
70617042 zend_pm_label_set_next (& context , false_label );
70627043
70637044 for (uint32_t i = 0 ; i < context .num_bindings ; i ++ ) {
70647045 znode var_node ;
70657046 var_node .op_type = IS_TMP_VAR ;
7066- var_node .u .op .var = context .first_tmp + i ;
7047+ var_node .u .op .var = context .first_binding_tmp + i ;
70677048 zend_emit_op (NULL , ZEND_FREE , & var_node , NULL );
70687049 }
70697050
0 commit comments