]> granicus.if.org Git - php/commitdiff
Fixed optimization patterns
authorDmitry Stogov <dmitry@zend.com>
Fri, 20 Mar 2015 02:24:04 +0000 (05:24 +0300)
committerDmitry Stogov <dmitry@zend.com>
Fri, 20 Mar 2015 02:24:04 +0000 (05:24 +0300)
ext/opcache/Optimizer/block_pass.c
ext/opcache/Optimizer/pass1_5.c
ext/opcache/Optimizer/zend_optimizer.c

index 3f57183ed376d2ecb3aa8a6c2c3d901f7a9c1e72..555c2778cfb7f9eb40c0f0f5649d6dcf4a990594 100644 (file)
@@ -940,11 +940,8 @@ static void zend_optimize_block(zend_code_block *block, zend_op_array *op_array,
                        }
 
                        VAR_UNSET(opline->op1);
-                       if (ZEND_OP1_TYPE(src) == IS_UNUSED) {
-                               /* 5.3 may use IS_UNUSED as first argument to ZEND_ADD_... */
+                       if (opline->opcode != ZEND_CONCAT) {
                                opline->opcode = ZEND_ADD_STRING;
-                       } else {
-                               opline->opcode = ZEND_CONCAT;
                        }
                        COPY_NODE(opline->op1, src->op1);
                        old_len = Z_STRLEN(ZEND_OP2_LITERAL(src));
@@ -1039,45 +1036,47 @@ static void zend_optimize_block(zend_code_block *block, zend_op_array *op_array,
                        VAR_UNSET(opline->op1);
                        COPY_NODE(opline->op1, src->op1);
                        MAKE_NOP(src);
-               } else if ((opline->opcode == ZEND_ADD_STRING ||
-                                       opline->opcode == ZEND_ADD_CHAR ||
-                                       opline->opcode == ZEND_ADD_VAR ||
-                                       opline->opcode == ZEND_CONCAT) &&
-                                       ZEND_OP1_TYPE(opline) == IS_TMP_VAR &&
-                                       VAR_SOURCE(opline->op1) &&
-                                       VAR_SOURCE(opline->op1)->opcode == ZEND_CONCAT &&
-                                       ZEND_OP2_TYPE(VAR_SOURCE(opline->op1)) == IS_CONST &&
-                                       Z_TYPE(ZEND_OP2_LITERAL(VAR_SOURCE(opline->op1))) == IS_STRING &&
-                                       Z_STRLEN(ZEND_OP2_LITERAL(VAR_SOURCE(opline->op1))) == 0) {
-                       /* convert T = CONCAT(X,''), T = ADD_STRING(T, Y) to T = CONCAT(X,Y) */
-                       zend_op *src = VAR_SOURCE(opline->op1);
-                       VAR_UNSET(opline->op1);
-                       COPY_NODE(opline->op1, src->op1);
-                       if (opline->opcode == ZEND_ADD_CHAR) {
-                               char c = (char)Z_LVAL(ZEND_OP2_LITERAL(opline));
-                               ZVAL_STRINGL(&ZEND_OP2_LITERAL(opline), &c, 1);
+               } else if (opline->opcode == ZEND_CONCAT) {
+                       if ((ZEND_OP1_TYPE(opline) & (IS_TMP_VAR|IS_VAR)) &&
+                               VAR_SOURCE(opline->op1) &&
+                               VAR_SOURCE(opline->op1)->opcode == ZEND_CAST &&
+                               VAR_SOURCE(opline->op1)->extended_value == IS_STRING) {
+                               /* convert T1 = CAST(STRING, X), T2 = CONCAT(T1, Y) to T2 = CONCAT(X,Y) */
+                               zend_op *src = VAR_SOURCE(opline->op1);
+                               VAR_UNSET(opline->op1);
+                               COPY_NODE(opline->op1, src->op1);
+                               MAKE_NOP(src);
                        }
-                       opline->opcode = ZEND_CONCAT;
-                       literal_dtor(&ZEND_OP2_LITERAL(src)); /* will take care of empty_string too */
-                       MAKE_NOP(src);
-               } else if ((opline->opcode == ZEND_ADD_STRING ||
-                                       opline->opcode == ZEND_ADD_CHAR ||
-                                       opline->opcode == ZEND_ADD_VAR ||
-                                       opline->opcode == ZEND_CONCAT) &&
-                                       (ZEND_OP1_TYPE(opline) & (IS_TMP_VAR|IS_VAR)) &&
-                                       VAR_SOURCE(opline->op1) &&
-                                       VAR_SOURCE(opline->op1)->opcode == ZEND_CAST &&
-                                       VAR_SOURCE(opline->op1)->extended_value == IS_STRING) {
-                       /* convert T1 = CAST(STRING, X), T2 = CONCAT(T1, Y) to T2 = CONCAT(X,Y) */
-                       zend_op *src = VAR_SOURCE(opline->op1);
-                       VAR_UNSET(opline->op1);
-                       COPY_NODE(opline->op1, src->op1);
-                       if (opline->opcode == ZEND_ADD_CHAR) {
-                               char c = (char)Z_LVAL(ZEND_OP2_LITERAL(opline));
-                               ZVAL_STRINGL(&ZEND_OP2_LITERAL(opline), &c, 1);
+                       if ((ZEND_OP2_TYPE(opline) & (IS_TMP_VAR|IS_VAR)) &&
+                               VAR_SOURCE(opline->op2) &&
+                               VAR_SOURCE(opline->op2)->opcode == ZEND_CAST &&
+                               VAR_SOURCE(opline->op2)->extended_value == IS_STRING) {
+                               /* convert T1 = CAST(STRING, X), T2 = CONCAT(Y, T1) to T2 = CONCAT(Y,X) */
+                               zend_op *src = VAR_SOURCE(opline->op2);
+                               VAR_UNSET(opline->op2);
+                               COPY_NODE(opline->op2, src->op1);
+                               MAKE_NOP(src);
+                       }
+                       if (ZEND_OP1_TYPE(opline) == IS_CONST &&
+                           Z_TYPE(ZEND_OP1_LITERAL(opline)) == IS_STRING &&
+                           Z_STRLEN(ZEND_OP1_LITERAL(opline)) == 0) {
+                               /* convert CONCAT('', X) => CAST(STRING, X) */
+                               literal_dtor(&ZEND_OP1_LITERAL(opline));
+                               opline->opcode = ZEND_CAST;
+                               opline->extended_value = IS_STRING;
+                               COPY_NODE(opline->op1, opline->op2);
+                               opline->op2_type = IS_UNUSED;
+                               opline->op2.var = 0;
+                       } else if (ZEND_OP2_TYPE(opline) == IS_CONST &&
+                                  Z_TYPE(ZEND_OP2_LITERAL(opline)) == IS_STRING &&
+                                  Z_STRLEN(ZEND_OP2_LITERAL(opline)) == 0) {
+                               /* convert CONCAT(X, '') => CAST(STRING, X) */
+                               literal_dtor(&ZEND_OP2_LITERAL(opline));
+                               opline->opcode = ZEND_CAST;
+                               opline->extended_value = IS_STRING;
+                               opline->op2_type = IS_UNUSED;
+                               opline->op2.var = 0;
                        }
-                       opline->opcode = ZEND_CONCAT;
-                       MAKE_NOP(src);
                } else if (opline->opcode == ZEND_QM_ASSIGN &&
                                        ZEND_OP1_TYPE(opline) == ZEND_RESULT_TYPE(opline) &&
                                        ZEND_OP1(opline).var == ZEND_RESULT(opline).var) {
index f37084ed79c842abebf9b24f50aa7c43ebbf5d1f..031e0e3b375ffdd133e4cc3692102f8f81bc8a42 100644 (file)
@@ -87,11 +87,12 @@ void zend_optimizer_pass1(zend_op_array *op_array, zend_optimizer_ctx *ctx)
                                        break;
                                }
                                EG(error_reporting) = er;
-                               literal_dtor(&ZEND_OP1_LITERAL(opline));
-                               literal_dtor(&ZEND_OP2_LITERAL(opline));
-                               MAKE_NOP(opline);
 
-                               zend_optimizer_replace_by_const(op_array, opline + 1, IS_TMP_VAR, tv, &result);
+                               if (zend_optimizer_replace_by_const(op_array, opline + 1, IS_TMP_VAR, tv, &result)) {
+                                       literal_dtor(&ZEND_OP1_LITERAL(opline));
+                                       literal_dtor(&ZEND_OP2_LITERAL(opline));
+                                       MAKE_NOP(opline);
+                               }
                        }
                        break;
 
@@ -124,10 +125,10 @@ void zend_optimizer_pass1(zend_op_array *op_array, zend_optimizer_ctx *ctx)
                                                break;
                                }
 
-                               literal_dtor(&ZEND_OP1_LITERAL(opline));
-                               MAKE_NOP(opline);
-
-                               zend_optimizer_replace_by_const(op_array, opline + 1, type, tv, &res);
+                               if (zend_optimizer_replace_by_const(op_array, opline + 1, type, tv, &res)) {
+                                       literal_dtor(&ZEND_OP1_LITERAL(opline));
+                                       MAKE_NOP(opline);
+                               }
                        } else if (opline->extended_value == _IS_BOOL) {
                                /* T = CAST(X, IS_BOOL) => T = BOOL(X) */
                                opline->opcode = ZEND_BOOL;
@@ -151,10 +152,11 @@ void zend_optimizer_pass1(zend_op_array *op_array, zend_optimizer_ctx *ctx)
                                        break;
                                }
                                EG(error_reporting) = er;
-                               literal_dtor(&ZEND_OP1_LITERAL(opline));
-                               MAKE_NOP(opline);
 
-                               zend_optimizer_replace_by_const(op_array, opline + 1, IS_TMP_VAR, tv, &result);
+                               if (zend_optimizer_replace_by_const(op_array, opline + 1, IS_TMP_VAR, tv, &result)) {
+                                       literal_dtor(&ZEND_OP1_LITERAL(opline));
+                                       MAKE_NOP(opline);
+                               }
                        }
                        break;
 
@@ -190,6 +192,7 @@ void zend_optimizer_pass1(zend_op_array *op_array, zend_optimizer_ctx *ctx)
                                last_op = next_op;
                                final_length += (requires_conversion? 1 : Z_STRLEN(ZEND_OP2_LITERAL(opline)));
                                str = zend_string_alloc(final_length, 0);
+                               str->len = final_length;
                                ptr = str->val;
                                ptr[final_length] = '\0';
                                if (requires_conversion) { /* ZEND_ADD_CHAR */
@@ -201,11 +204,10 @@ void zend_optimizer_pass1(zend_op_array *op_array, zend_optimizer_ctx *ctx)
                                        ptr++;
                                } else { /* ZEND_ADD_STRING */
                                        memcpy(ptr, Z_STRVAL(ZEND_OP2_LITERAL(opline)), Z_STRLEN(ZEND_OP2_LITERAL(opline)));
-                                       zend_string_release(Z_STR(ZEND_OP2_LITERAL(opline)));
-                                       Z_STR(ZEND_OP2_LITERAL(opline)) = str;
                                        ptr += Z_STRLEN(ZEND_OP2_LITERAL(opline));
+                                       zend_string_release(Z_STR(ZEND_OP2_LITERAL(opline)));
+                                       ZVAL_NEW_STR(&ZEND_OP2_LITERAL(opline), str);
                                }
-                               Z_STRLEN(ZEND_OP2_LITERAL(opline)) = final_length;
                                next_op = opline + 1;
                                while (next_op < last_op) {
                                        if (next_op->opcode == ZEND_ADD_STRING) {
@@ -246,9 +248,10 @@ void zend_optimizer_pass1(zend_op_array *op_array, zend_optimizer_ctx *ctx)
                                if ((offset = zend_get_constant_str("__COMPILER_HALT_OFFSET__", sizeof("__COMPILER_HALT_OFFSET__") - 1)) != NULL) {
                                        uint32_t tv = ZEND_RESULT(opline).var;
 
-                                       literal_dtor(&ZEND_OP2_LITERAL(opline));
-                                       MAKE_NOP(opline);
-                                       zend_optimizer_replace_by_const(op_array, opline, IS_TMP_VAR, tv, offset);
+                                       if (zend_optimizer_replace_by_const(op_array, opline, IS_TMP_VAR, tv, offset)) {
+                                               literal_dtor(&ZEND_OP2_LITERAL(opline));
+                                               MAKE_NOP(opline);
+                                       }
                                }
                                EG(current_execute_data) = orig_execute_data;
                                break;
@@ -269,9 +272,10 @@ void zend_optimizer_pass1(zend_op_array *op_array, zend_optimizer_ctx *ctx)
                                if (Z_TYPE(c) == IS_CONSTANT_AST) {
                                        break;
                                }
-                               literal_dtor(&ZEND_OP2_LITERAL(opline));
-                               MAKE_NOP(opline);
-                               zend_optimizer_replace_by_const(op_array, opline, IS_TMP_VAR, tv, &c);
+                               if (zend_optimizer_replace_by_const(op_array, opline, IS_TMP_VAR, tv, &c)) {
+                                       literal_dtor(&ZEND_OP2_LITERAL(opline));
+                                       MAKE_NOP(opline);
+                               }
                        }
 
                        /* class constant */
@@ -333,9 +337,10 @@ void zend_optimizer_pass1(zend_op_array *op_array, zend_optimizer_ctx *ctx)
                                                } else {
                                                        MAKE_NOP((opline - 1));
                                                }
-                                               literal_dtor(&ZEND_OP2_LITERAL(opline));
-                                               MAKE_NOP(opline);
-                                               zend_optimizer_replace_by_const(op_array, opline, IS_TMP_VAR, tv, &t);
+                                               if (zend_optimizer_replace_by_const(op_array, opline, IS_TMP_VAR, tv, &t)) {
+                                                       literal_dtor(&ZEND_OP2_LITERAL(opline));
+                                                       MAKE_NOP(opline);
+                                               }
                                        }
                                }
                        }
@@ -559,9 +564,10 @@ void zend_optimizer_pass1(zend_op_array *op_array, zend_optimizer_ctx *ctx)
                                zval t;
 
                                ZVAL_LONG(&t, Z_STRLEN(ZEND_OP1_LITERAL(opline)));
-                               zend_optimizer_replace_by_const(op_array, opline + 1, IS_TMP_VAR, ZEND_RESULT(opline).var, &t);
-                               literal_dtor(&ZEND_OP1_LITERAL(opline));
-                               MAKE_NOP(opline);
+                               if (zend_optimizer_replace_by_const(op_array, opline + 1, IS_TMP_VAR, ZEND_RESULT(opline).var, &t)) {
+                                       literal_dtor(&ZEND_OP1_LITERAL(opline));
+                                       MAKE_NOP(opline);
+                               }
                        }
                        break;
                case ZEND_DEFINED:
@@ -572,9 +578,10 @@ void zend_optimizer_pass1(zend_op_array *op_array, zend_optimizer_ctx *ctx)
                                        break;
                                }
                                ZVAL_TRUE(&c);
-                               zend_optimizer_replace_by_const(op_array, opline, IS_TMP_VAR, tv, &c);
-                               literal_dtor(&ZEND_OP1_LITERAL(opline));
-                               MAKE_NOP(opline);
+                               if (zend_optimizer_replace_by_const(op_array, opline, IS_TMP_VAR, tv, &c)) {
+                                       literal_dtor(&ZEND_OP1_LITERAL(opline));
+                                       MAKE_NOP(opline);
+                               }
                        }
                        break;
                case ZEND_DECLARE_CONST:
index 7be076cb7f5b2db8bfe2328a5cbc9b6a1217ae65..d0d67a57dad49220c95faebedfa4bb01b1602fc8 100644 (file)
@@ -158,6 +158,9 @@ void zend_optimizer_update_op2_const(zend_op_array *op_array,
                Z_CACHE_SLOT(op_array->literals[opline->op2.constant]) = op_array->cache_size;
                op_array->cache_size += sizeof(void*);
                return;
+       } else if (opline->opcode == ZEND_ADD_VAR) {
+               convert_to_string(val);
+               opline->opcode = ZEND_ADD_STRING;
        }
        opline->op2.constant = zend_optimizer_add_literal(op_array, val);
        if (Z_TYPE_P(val) == IS_STRING) {
@@ -306,6 +309,7 @@ int zend_optimizer_replace_by_const(zend_op_array *op_array,
                                case ZEND_SEND_VAR_NO_REF:
                                        if (opline->extended_value & ZEND_ARG_COMPILE_TIME_BOUND) {
                                                if (opline->extended_value & ZEND_ARG_SEND_BY_REF) {
+                                                       zval_dtor(val);
                                                        return 0;
                                                }
                                                opline->extended_value = 0;
@@ -374,6 +378,7 @@ int zend_optimizer_replace_by_const(zend_op_array *op_array,
                        ZEND_OP2(opline).var == var) {
                        switch (opline->opcode) {
                                case ZEND_ASSIGN_REF:
+                                       zval_dtor(val);
                                        return 0;
                                default:
                                        break;