]> granicus.if.org Git - php/commitdiff
Array addition is not commutative
authorDmitry Stogov <dmitry@zend.com>
Fri, 15 Dec 2017 11:40:19 +0000 (14:40 +0300)
committerDmitry Stogov <dmitry@zend.com>
Fri, 15 Dec 2017 11:40:19 +0000 (14:40 +0300)
Zend/zend_vm_def.h
Zend/zend_vm_execute.h
Zend/zend_vm_opcodes.c

index 661db7c5ecca32b93677f52a4620bae3200f6963..01cd3435c32f59a9dfde9574488769bc2e0e2275 100644 (file)
@@ -25,7 +25,7 @@
  * php zend_vm_gen.php
  */
 
-ZEND_VM_HANDLER(1, ZEND_ADD, CONST|TMPVAR|CV, CONST|TMPVAR|CV, SPEC(COMMUTATIVE))
+ZEND_VM_HANDLER(1, ZEND_ADD, CONST|TMPVAR|CV, CONST|TMPVAR|CV)
 {
        USE_OPLINE
        zend_free_op free_op1, free_op2;
index 69b8eec7b9e76389596a17f9b1565f0f13381823..fef5784b06eac0ddc518d9a3ba43d986eace1741 100644 (file)
@@ -6783,6 +6783,49 @@ static ZEND_VM_HOT ZEND_OPCODE_HANDLER_RET ZEND_FASTCALL ZEND_IS_SMALLER_OR_EQUA
        ZEND_VM_NEXT_OPCODE();
 }
 
+static ZEND_OPCODE_HANDLER_RET ZEND_FASTCALL ZEND_ADD_SPEC_CONST_TMPVAR_HANDLER(ZEND_OPCODE_HANDLER_ARGS)
+{
+       USE_OPLINE
+       zend_free_op free_op2;
+       zval *op1, *op2, *result;
+
+       op1 = RT_CONSTANT(opline, opline->op1);
+       op2 = _get_zval_ptr_var(opline->op2.var, &free_op2 EXECUTE_DATA_CC);
+       if (EXPECTED(Z_TYPE_INFO_P(op1) == IS_LONG)) {
+               if (EXPECTED(Z_TYPE_INFO_P(op2) == IS_LONG)) {
+                       result = EX_VAR(opline->result.var);
+                       fast_long_add_function(result, op1, op2);
+                       ZEND_VM_NEXT_OPCODE();
+               } else if (EXPECTED(Z_TYPE_INFO_P(op2) == IS_DOUBLE)) {
+                       result = EX_VAR(opline->result.var);
+                       ZVAL_DOUBLE(result, ((double)Z_LVAL_P(op1)) + Z_DVAL_P(op2));
+                       ZEND_VM_NEXT_OPCODE();
+               }
+       } else if (EXPECTED(Z_TYPE_INFO_P(op1) == IS_DOUBLE)) {
+               if (EXPECTED(Z_TYPE_INFO_P(op2) == IS_DOUBLE)) {
+                       result = EX_VAR(opline->result.var);
+                       ZVAL_DOUBLE(result, Z_DVAL_P(op1) + Z_DVAL_P(op2));
+                       ZEND_VM_NEXT_OPCODE();
+               } else if (EXPECTED(Z_TYPE_INFO_P(op2) == IS_LONG)) {
+                       result = EX_VAR(opline->result.var);
+                       ZVAL_DOUBLE(result, Z_DVAL_P(op1) + ((double)Z_LVAL_P(op2)));
+                       ZEND_VM_NEXT_OPCODE();
+               }
+       }
+
+       SAVE_OPLINE();
+       if (IS_CONST == IS_CV && UNEXPECTED(Z_TYPE_INFO_P(op1) == IS_UNDEF)) {
+               op1 = GET_OP1_UNDEF_CV(op1, BP_VAR_R);
+       }
+       if ((IS_TMP_VAR|IS_VAR) == IS_CV && UNEXPECTED(Z_TYPE_INFO_P(op2) == IS_UNDEF)) {
+               op2 = GET_OP2_UNDEF_CV(op2, BP_VAR_R);
+       }
+       add_function(EX_VAR(opline->result.var), op1, op2);
+
+       zval_ptr_dtor_nogc(free_op2);
+       ZEND_VM_NEXT_OPCODE_CHECK_EXCEPTION();
+}
+
 static ZEND_OPCODE_HANDLER_RET ZEND_FASTCALL ZEND_SUB_SPEC_CONST_TMPVAR_HANDLER(ZEND_OPCODE_HANDLER_ARGS)
 {
        USE_OPLINE
@@ -9920,6 +9963,49 @@ static ZEND_OPCODE_HANDLER_RET ZEND_FASTCALL ZEND_FUNC_GET_ARGS_SPEC_CONST_UNUSE
        ZEND_VM_NEXT_OPCODE();
 }
 
+static ZEND_OPCODE_HANDLER_RET ZEND_FASTCALL ZEND_ADD_SPEC_CONST_CV_HANDLER(ZEND_OPCODE_HANDLER_ARGS)
+{
+       USE_OPLINE
+
+       zval *op1, *op2, *result;
+
+       op1 = RT_CONSTANT(opline, opline->op1);
+       op2 = _get_zval_ptr_cv_undef(opline->op2.var EXECUTE_DATA_CC);
+       if (EXPECTED(Z_TYPE_INFO_P(op1) == IS_LONG)) {
+               if (EXPECTED(Z_TYPE_INFO_P(op2) == IS_LONG)) {
+                       result = EX_VAR(opline->result.var);
+                       fast_long_add_function(result, op1, op2);
+                       ZEND_VM_NEXT_OPCODE();
+               } else if (EXPECTED(Z_TYPE_INFO_P(op2) == IS_DOUBLE)) {
+                       result = EX_VAR(opline->result.var);
+                       ZVAL_DOUBLE(result, ((double)Z_LVAL_P(op1)) + Z_DVAL_P(op2));
+                       ZEND_VM_NEXT_OPCODE();
+               }
+       } else if (EXPECTED(Z_TYPE_INFO_P(op1) == IS_DOUBLE)) {
+               if (EXPECTED(Z_TYPE_INFO_P(op2) == IS_DOUBLE)) {
+                       result = EX_VAR(opline->result.var);
+                       ZVAL_DOUBLE(result, Z_DVAL_P(op1) + Z_DVAL_P(op2));
+                       ZEND_VM_NEXT_OPCODE();
+               } else if (EXPECTED(Z_TYPE_INFO_P(op2) == IS_LONG)) {
+                       result = EX_VAR(opline->result.var);
+                       ZVAL_DOUBLE(result, Z_DVAL_P(op1) + ((double)Z_LVAL_P(op2)));
+                       ZEND_VM_NEXT_OPCODE();
+               }
+       }
+
+       SAVE_OPLINE();
+       if (IS_CONST == IS_CV && UNEXPECTED(Z_TYPE_INFO_P(op1) == IS_UNDEF)) {
+               op1 = GET_OP1_UNDEF_CV(op1, BP_VAR_R);
+       }
+       if (IS_CV == IS_CV && UNEXPECTED(Z_TYPE_INFO_P(op2) == IS_UNDEF)) {
+               op2 = GET_OP2_UNDEF_CV(op2, BP_VAR_R);
+       }
+       add_function(EX_VAR(opline->result.var), op1, op2);
+
+
+       ZEND_VM_NEXT_OPCODE_CHECK_EXCEPTION();
+}
+
 static ZEND_OPCODE_HANDLER_RET ZEND_FASTCALL ZEND_SUB_SPEC_CONST_CV_HANDLER(ZEND_OPCODE_HANDLER_ARGS)
 {
        USE_OPLINE
@@ -17284,6 +17370,49 @@ try_instanceof:
        ZEND_VM_NEXT_OPCODE_CHECK_EXCEPTION();
 }
 
+static ZEND_OPCODE_HANDLER_RET ZEND_FASTCALL ZEND_ADD_SPEC_TMPVAR_CV_HANDLER(ZEND_OPCODE_HANDLER_ARGS)
+{
+       USE_OPLINE
+       zend_free_op free_op1;
+       zval *op1, *op2, *result;
+
+       op1 = _get_zval_ptr_var(opline->op1.var, &free_op1 EXECUTE_DATA_CC);
+       op2 = _get_zval_ptr_cv_undef(opline->op2.var EXECUTE_DATA_CC);
+       if (EXPECTED(Z_TYPE_INFO_P(op1) == IS_LONG)) {
+               if (EXPECTED(Z_TYPE_INFO_P(op2) == IS_LONG)) {
+                       result = EX_VAR(opline->result.var);
+                       fast_long_add_function(result, op1, op2);
+                       ZEND_VM_NEXT_OPCODE();
+               } else if (EXPECTED(Z_TYPE_INFO_P(op2) == IS_DOUBLE)) {
+                       result = EX_VAR(opline->result.var);
+                       ZVAL_DOUBLE(result, ((double)Z_LVAL_P(op1)) + Z_DVAL_P(op2));
+                       ZEND_VM_NEXT_OPCODE();
+               }
+       } else if (EXPECTED(Z_TYPE_INFO_P(op1) == IS_DOUBLE)) {
+               if (EXPECTED(Z_TYPE_INFO_P(op2) == IS_DOUBLE)) {
+                       result = EX_VAR(opline->result.var);
+                       ZVAL_DOUBLE(result, Z_DVAL_P(op1) + Z_DVAL_P(op2));
+                       ZEND_VM_NEXT_OPCODE();
+               } else if (EXPECTED(Z_TYPE_INFO_P(op2) == IS_LONG)) {
+                       result = EX_VAR(opline->result.var);
+                       ZVAL_DOUBLE(result, Z_DVAL_P(op1) + ((double)Z_LVAL_P(op2)));
+                       ZEND_VM_NEXT_OPCODE();
+               }
+       }
+
+       SAVE_OPLINE();
+       if ((IS_TMP_VAR|IS_VAR) == IS_CV && UNEXPECTED(Z_TYPE_INFO_P(op1) == IS_UNDEF)) {
+               op1 = GET_OP1_UNDEF_CV(op1, BP_VAR_R);
+       }
+       if (IS_CV == IS_CV && UNEXPECTED(Z_TYPE_INFO_P(op2) == IS_UNDEF)) {
+               op2 = GET_OP2_UNDEF_CV(op2, BP_VAR_R);
+       }
+       add_function(EX_VAR(opline->result.var), op1, op2);
+       zval_ptr_dtor_nogc(free_op1);
+
+       ZEND_VM_NEXT_OPCODE_CHECK_EXCEPTION();
+}
+
 static ZEND_OPCODE_HANDLER_RET ZEND_FASTCALL ZEND_SUB_SPEC_TMPVAR_CV_HANDLER(ZEND_OPCODE_HANDLER_ARGS)
 {
        USE_OPLINE
@@ -53370,20 +53499,20 @@ ZEND_API void execute_ex(zend_execute_data *ex)
                static const void * const labels[] = {
                        (void*)&&ZEND_NOP_SPEC_LABEL,
                        (void*)&&ZEND_ADD_SPEC_CONST_CONST_LABEL,
+                       (void*)&&ZEND_ADD_SPEC_CONST_TMPVAR_LABEL,
+                       (void*)&&ZEND_ADD_SPEC_CONST_TMPVAR_LABEL,
                        (void*)&&ZEND_NULL_LABEL,
-                       (void*)&&ZEND_NULL_LABEL,
-                       (void*)&&ZEND_NULL_LABEL,
-                       (void*)&&ZEND_NULL_LABEL,
+                       (void*)&&ZEND_ADD_SPEC_CONST_CV_LABEL,
                        (void*)&&ZEND_ADD_SPEC_TMPVAR_CONST_LABEL,
                        (void*)&&ZEND_ADD_SPEC_TMPVAR_TMPVAR_LABEL,
                        (void*)&&ZEND_ADD_SPEC_TMPVAR_TMPVAR_LABEL,
                        (void*)&&ZEND_NULL_LABEL,
-                       (void*)&&ZEND_NULL_LABEL,
+                       (void*)&&ZEND_ADD_SPEC_TMPVAR_CV_LABEL,
                        (void*)&&ZEND_ADD_SPEC_TMPVAR_CONST_LABEL,
                        (void*)&&ZEND_ADD_SPEC_TMPVAR_TMPVAR_LABEL,
                        (void*)&&ZEND_ADD_SPEC_TMPVAR_TMPVAR_LABEL,
                        (void*)&&ZEND_NULL_LABEL,
-                       (void*)&&ZEND_NULL_LABEL,
+                       (void*)&&ZEND_ADD_SPEC_TMPVAR_CV_LABEL,
                        (void*)&&ZEND_NULL_LABEL,
                        (void*)&&ZEND_NULL_LABEL,
                        (void*)&&ZEND_NULL_LABEL,
@@ -58789,6 +58918,9 @@ ZEND_API void execute_ex(zend_execute_data *ex)
                        HYBRID_CASE(ZEND_IS_SMALLER_OR_EQUAL_DOUBLE_SPEC_CONST_TMPVARCV_JMPNZ):
                                ZEND_IS_SMALLER_OR_EQUAL_DOUBLE_SPEC_CONST_TMPVARCV_JMPNZ_HANDLER(ZEND_OPCODE_HANDLER_ARGS_PASSTHRU);
                                HYBRID_BREAK();
+                       HYBRID_CASE(ZEND_ADD_SPEC_CONST_TMPVAR):
+                               ZEND_ADD_SPEC_CONST_TMPVAR_HANDLER(ZEND_OPCODE_HANDLER_ARGS_PASSTHRU);
+                               HYBRID_BREAK();
                        HYBRID_CASE(ZEND_SUB_SPEC_CONST_TMPVAR):
                                ZEND_SUB_SPEC_CONST_TMPVAR_HANDLER(ZEND_OPCODE_HANDLER_ARGS_PASSTHRU);
                                HYBRID_BREAK();
@@ -58981,6 +59113,9 @@ ZEND_API void execute_ex(zend_execute_data *ex)
                        HYBRID_CASE(ZEND_FUNC_GET_ARGS_SPEC_CONST_UNUSED):
                                ZEND_FUNC_GET_ARGS_SPEC_CONST_UNUSED_HANDLER(ZEND_OPCODE_HANDLER_ARGS_PASSTHRU);
                                HYBRID_BREAK();
+                       HYBRID_CASE(ZEND_ADD_SPEC_CONST_CV):
+                               ZEND_ADD_SPEC_CONST_CV_HANDLER(ZEND_OPCODE_HANDLER_ARGS_PASSTHRU);
+                               HYBRID_BREAK();
                        HYBRID_CASE(ZEND_SUB_SPEC_CONST_CV):
                                ZEND_SUB_SPEC_CONST_CV_HANDLER(ZEND_OPCODE_HANDLER_ARGS_PASSTHRU);
                                HYBRID_BREAK();
@@ -59659,6 +59794,9 @@ ZEND_API void execute_ex(zend_execute_data *ex)
                        HYBRID_CASE(ZEND_INSTANCEOF_SPEC_TMPVAR_UNUSED):
                                ZEND_INSTANCEOF_SPEC_TMPVAR_UNUSED_HANDLER(ZEND_OPCODE_HANDLER_ARGS_PASSTHRU);
                                HYBRID_BREAK();
+                       HYBRID_CASE(ZEND_ADD_SPEC_TMPVAR_CV):
+                               ZEND_ADD_SPEC_TMPVAR_CV_HANDLER(ZEND_OPCODE_HANDLER_ARGS_PASSTHRU);
+                               HYBRID_BREAK();
                        HYBRID_CASE(ZEND_SUB_SPEC_TMPVAR_CV):
                                ZEND_SUB_SPEC_TMPVAR_CV_HANDLER(ZEND_OPCODE_HANDLER_ARGS_PASSTHRU);
                                HYBRID_BREAK();
@@ -62286,20 +62424,20 @@ void zend_init_opcodes_handlers(void)
        static const void * const labels[] = {
                ZEND_NOP_SPEC_HANDLER,
                ZEND_ADD_SPEC_CONST_CONST_HANDLER,
+               ZEND_ADD_SPEC_CONST_TMPVAR_HANDLER,
+               ZEND_ADD_SPEC_CONST_TMPVAR_HANDLER,
                ZEND_NULL_HANDLER,
-               ZEND_NULL_HANDLER,
-               ZEND_NULL_HANDLER,
-               ZEND_NULL_HANDLER,
+               ZEND_ADD_SPEC_CONST_CV_HANDLER,
                ZEND_ADD_SPEC_TMPVAR_CONST_HANDLER,
                ZEND_ADD_SPEC_TMPVAR_TMPVAR_HANDLER,
                ZEND_ADD_SPEC_TMPVAR_TMPVAR_HANDLER,
                ZEND_NULL_HANDLER,
-               ZEND_NULL_HANDLER,
+               ZEND_ADD_SPEC_TMPVAR_CV_HANDLER,
                ZEND_ADD_SPEC_TMPVAR_CONST_HANDLER,
                ZEND_ADD_SPEC_TMPVAR_TMPVAR_HANDLER,
                ZEND_ADD_SPEC_TMPVAR_TMPVAR_HANDLER,
                ZEND_NULL_HANDLER,
-               ZEND_NULL_HANDLER,
+               ZEND_ADD_SPEC_TMPVAR_CV_HANDLER,
                ZEND_NULL_HANDLER,
                ZEND_NULL_HANDLER,
                ZEND_NULL_HANDLER,
@@ -67234,7 +67372,7 @@ void zend_init_opcodes_handlers(void)
        };
        static const uint32_t specs[] = {
                0,
-               1 | SPEC_RULE_OP1 | SPEC_RULE_OP2 | SPEC_RULE_COMMUTATIVE,
+               1 | SPEC_RULE_OP1 | SPEC_RULE_OP2,
                26 | SPEC_RULE_OP1 | SPEC_RULE_OP2,
                51 | SPEC_RULE_OP1 | SPEC_RULE_OP2 | SPEC_RULE_COMMUTATIVE,
                76 | SPEC_RULE_OP1 | SPEC_RULE_OP2,
@@ -67630,24 +67768,30 @@ ZEND_API void zend_vm_set_opcode_handler_ex(zend_op* op, uint32_t op1_info, uint
        uint32_t spec = zend_spec_handlers[opcode];
        switch (opcode) {
                case ZEND_ADD:
-                       if (op->op1_type < op->op2_type) {
-                               zend_swap_operands(op);
-                       }
                        if (res_info == MAY_BE_LONG && op1_info == MAY_BE_LONG && op2_info == MAY_BE_LONG) {
                                if (op->op1_type == IS_CONST && op->op2_type == IS_CONST) {
                                        break;
                                }
                                spec = 3931 | SPEC_RULE_OP1 | SPEC_RULE_OP2 | SPEC_RULE_COMMUTATIVE;
+                               if (op->op1_type < op->op2_type) {
+                                       zend_swap_operands(op);
+                               }
                        } else if (op1_info == MAY_BE_LONG && op2_info == MAY_BE_LONG) {
                                if (op->op1_type == IS_CONST && op->op2_type == IS_CONST) {
                                        break;
                                }
                                spec = 3956 | SPEC_RULE_OP1 | SPEC_RULE_OP2 | SPEC_RULE_COMMUTATIVE;
+                               if (op->op1_type < op->op2_type) {
+                                       zend_swap_operands(op);
+                               }
                        } else if (op1_info == MAY_BE_DOUBLE && op2_info == MAY_BE_DOUBLE) {
                                if (op->op1_type == IS_CONST && op->op2_type == IS_CONST) {
                                        break;
                                }
                                spec = 3981 | SPEC_RULE_OP1 | SPEC_RULE_OP2 | SPEC_RULE_COMMUTATIVE;
+                               if (op->op1_type < op->op2_type) {
+                                       zend_swap_operands(op);
+                               }
                        }
                        break;
                case ZEND_SUB:
index 46a46e09811957455d1cb079e90403efb77ff541..44b8a2df1928de62a3b4b431879bc8c6811deee8 100644 (file)
@@ -225,7 +225,7 @@ static const char *zend_vm_opcodes_names[199] = {
 
 static uint32_t zend_vm_opcodes_flags[199] = {
        0x00000000,
-       0x80000707,
+       0x00000707,
        0x00000707,
        0x80000707,
        0x00000707,