]> granicus.if.org Git - php/commitdiff
CONCAT optimization
authorDmitry Stogov <dmitry@zend.com>
Wed, 3 Jun 2015 08:15:28 +0000 (11:15 +0300)
committerDmitry Stogov <dmitry@zend.com>
Wed, 3 Jun 2015 08:15:28 +0000 (11:15 +0300)
Zend/zend_vm_def.h
Zend/zend_vm_execute.h

index 12c82282e5b65ed2ec0fdf865d6758b1d1be49cc..31e4047301b3a8b57759b66385e236a1a991f862 100644 (file)
@@ -248,12 +248,53 @@ ZEND_VM_HANDLER(8, ZEND_CONCAT, CONST|TMPVAR|CV, CONST|TMPVAR|CV)
 {
        USE_OPLINE
        zend_free_op free_op1, free_op2;
+       zval *op1, *op2;
 
        SAVE_OPLINE();
-       concat_function(EX_VAR(opline->result.var),
-               GET_OP1_ZVAL_PTR(BP_VAR_R),
-               GET_OP2_ZVAL_PTR(BP_VAR_R));
-       FREE_OP1();
+       op1 = GET_OP1_ZVAL_PTR(BP_VAR_R);
+       op2 = GET_OP2_ZVAL_PTR(BP_VAR_R);
+
+       do {
+               if ((OP1_TYPE == IS_CONST || EXPECTED(Z_TYPE_P(op1) == IS_STRING)) &&
+                   (OP2_TYPE == IS_CONST || EXPECTED(Z_TYPE_P(op2) == IS_STRING))) {
+                       zend_string *op1_str = Z_STR_P(op1);
+                       zend_string *op2_str = Z_STR_P(op2);
+                       zend_string *str;
+
+                       if (OP1_TYPE != IS_CONST) {
+                               if (UNEXPECTED(op1_str->len == 0)) {
+                                       ZVAL_STR_COPY(EX_VAR(opline->result.var), op2_str);
+                                       FREE_OP1();
+                                       break;
+                               }
+                       }
+                       if (OP2_TYPE != IS_CONST) {
+                               if (UNEXPECTED(op2_str->len == 0)) {
+                                       ZVAL_STR_COPY(EX_VAR(opline->result.var), op1_str);
+                                       FREE_OP1();
+                                       break;
+                               }
+                       }
+                       if (OP1_TYPE != IS_CONST && OP1_TYPE != IS_CV &&
+                           !IS_INTERNED(op1_str) && GC_REFCOUNT(op1_str) == 1) {
+                           size_t len = op1_str->len;
+
+                               str = zend_string_realloc(op1_str, len + op2_str->len, 0);
+//                             memcpy(str->val, op1_str->val, op1_str->len);
+                               memcpy(str->val + len, op2_str->val, op2_str->len+1);
+                               ZVAL_NEW_STR(EX_VAR(opline->result.var), str);
+                               break;
+                       } else {
+                               str = zend_string_alloc(op1_str->len + op2_str->len, 0);
+                               memcpy(str->val, op1_str->val, op1_str->len);
+                               memcpy(str->val + op1_str->len, op2_str->val, op2_str->len+1);
+                               ZVAL_NEW_STR(EX_VAR(opline->result.var), str);
+                       }
+               } else {
+                       concat_function(EX_VAR(opline->result.var), op1, op2);
+               }
+               FREE_OP1();
+       } while (0);
        FREE_OP2();
        CHECK_EXCEPTION();
        ZEND_VM_NEXT_OPCODE();
@@ -2747,16 +2788,38 @@ ZEND_VM_HANDLER(53, ZEND_FAST_CONCAT, CONST|TMPVAR|CV, CONST|TMPVAR|CV)
        } else {
                op2_str = zval_get_string(op2);
        }
-       str = zend_string_alloc(op1_str->len + op2_str->len, 0);
-       memcpy(str->val, op1_str->val, op1_str->len);
-       memcpy(str->val + op1_str->len, op2_str->val, op2_str->len+1);
-       ZVAL_NEW_STR(EX_VAR(opline->result.var), str);
-       if (OP1_TYPE != IS_CONST) {
-               zend_string_release(op1_str);
-       }
-       if (OP2_TYPE != IS_CONST) {
-               zend_string_release(op2_str);
-       }
+       do {
+               if (OP1_TYPE != IS_CONST) {
+                       if (UNEXPECTED(op1_str->len == 0)) {
+                               if (OP2_TYPE == IS_CONST) {
+                                       zend_string_addref(op2_str);
+                               }
+                               ZVAL_STR(EX_VAR(opline->result.var), op2_str);
+                               zend_string_release(op1_str);
+                               break;
+                       }
+               }
+               if (OP2_TYPE != IS_CONST) {
+                       if (UNEXPECTED(op2_str->len == 0)) {
+                               if (OP1_TYPE == IS_CONST) {
+                                       zend_string_addref(op1_str);
+                               }
+                               ZVAL_STR(EX_VAR(opline->result.var), op1_str);
+                               zend_string_release(op2_str);
+                               break;
+                       }
+               }
+               str = zend_string_alloc(op1_str->len + op2_str->len, 0);
+               memcpy(str->val, op1_str->val, op1_str->len);
+               memcpy(str->val + op1_str->len, op2_str->val, op2_str->len+1);
+               ZVAL_NEW_STR(EX_VAR(opline->result.var), str);
+               if (OP1_TYPE != IS_CONST) {
+                       zend_string_release(op1_str);
+               }
+               if (OP2_TYPE != IS_CONST) {
+                       zend_string_release(op2_str);
+               }
+       } while (0);
        FREE_OP1();
        FREE_OP2();
        CHECK_EXCEPTION();
index 4c9a382fe7fd0a362b76140aa24e374b3c5cd297..bb2f7815f551c327390838b89378fde58e0498a3 100644 (file)
@@ -4659,12 +4659,53 @@ static ZEND_OPCODE_HANDLER_RET ZEND_FASTCALL ZEND_CONCAT_SPEC_CONST_CONST_HANDLE
 {
        USE_OPLINE
 
+       zval *op1, *op2;
 
        SAVE_OPLINE();
-       concat_function(EX_VAR(opline->result.var),
-               EX_CONSTANT(opline->op1),
-               EX_CONSTANT(opline->op2));
+       op1 = EX_CONSTANT(opline->op1);
+       op2 = EX_CONSTANT(opline->op2);
+
+       do {
+               if ((IS_CONST == IS_CONST || EXPECTED(Z_TYPE_P(op1) == IS_STRING)) &&
+                   (IS_CONST == IS_CONST || EXPECTED(Z_TYPE_P(op2) == IS_STRING))) {
+                       zend_string *op1_str = Z_STR_P(op1);
+                       zend_string *op2_str = Z_STR_P(op2);
+                       zend_string *str;
 
+                       if (IS_CONST != IS_CONST) {
+                               if (UNEXPECTED(op1_str->len == 0)) {
+                                       ZVAL_STR_COPY(EX_VAR(opline->result.var), op2_str);
+
+                                       break;
+                               }
+                       }
+                       if (IS_CONST != IS_CONST) {
+                               if (UNEXPECTED(op2_str->len == 0)) {
+                                       ZVAL_STR_COPY(EX_VAR(opline->result.var), op1_str);
+
+                                       break;
+                               }
+                       }
+                       if (IS_CONST != IS_CONST && IS_CONST != IS_CV &&
+                           !IS_INTERNED(op1_str) && GC_REFCOUNT(op1_str) == 1) {
+                           size_t len = op1_str->len;
+
+                               str = zend_string_realloc(op1_str, len + op2_str->len, 0);
+//                             memcpy(str->val, op1_str->val, op1_str->len);
+                               memcpy(str->val + len, op2_str->val, op2_str->len+1);
+                               ZVAL_NEW_STR(EX_VAR(opline->result.var), str);
+                               break;
+                       } else {
+                               str = zend_string_alloc(op1_str->len + op2_str->len, 0);
+                               memcpy(str->val, op1_str->val, op1_str->len);
+                               memcpy(str->val + op1_str->len, op2_str->val, op2_str->len+1);
+                               ZVAL_NEW_STR(EX_VAR(opline->result.var), str);
+                       }
+               } else {
+                       concat_function(EX_VAR(opline->result.var), op1, op2);
+               }
+
+       } while (0);
 
        CHECK_EXCEPTION();
        ZEND_VM_NEXT_OPCODE();
@@ -5533,16 +5574,38 @@ static ZEND_OPCODE_HANDLER_RET ZEND_FASTCALL ZEND_FAST_CONCAT_SPEC_CONST_CONST_H
        } else {
                op2_str = zval_get_string(op2);
        }
-       str = zend_string_alloc(op1_str->len + op2_str->len, 0);
-       memcpy(str->val, op1_str->val, op1_str->len);
-       memcpy(str->val + op1_str->len, op2_str->val, op2_str->len+1);
-       ZVAL_NEW_STR(EX_VAR(opline->result.var), str);
-       if (IS_CONST != IS_CONST) {
-               zend_string_release(op1_str);
-       }
-       if (IS_CONST != IS_CONST) {
-               zend_string_release(op2_str);
-       }
+       do {
+               if (IS_CONST != IS_CONST) {
+                       if (UNEXPECTED(op1_str->len == 0)) {
+                               if (IS_CONST == IS_CONST) {
+                                       zend_string_addref(op2_str);
+                               }
+                               ZVAL_STR(EX_VAR(opline->result.var), op2_str);
+                               zend_string_release(op1_str);
+                               break;
+                       }
+               }
+               if (IS_CONST != IS_CONST) {
+                       if (UNEXPECTED(op2_str->len == 0)) {
+                               if (IS_CONST == IS_CONST) {
+                                       zend_string_addref(op1_str);
+                               }
+                               ZVAL_STR(EX_VAR(opline->result.var), op1_str);
+                               zend_string_release(op2_str);
+                               break;
+                       }
+               }
+               str = zend_string_alloc(op1_str->len + op2_str->len, 0);
+               memcpy(str->val, op1_str->val, op1_str->len);
+               memcpy(str->val + op1_str->len, op2_str->val, op2_str->len+1);
+               ZVAL_NEW_STR(EX_VAR(opline->result.var), str);
+               if (IS_CONST != IS_CONST) {
+                       zend_string_release(op1_str);
+               }
+               if (IS_CONST != IS_CONST) {
+                       zend_string_release(op2_str);
+               }
+       } while (0);
 
 
        CHECK_EXCEPTION();
@@ -8545,12 +8608,53 @@ static ZEND_OPCODE_HANDLER_RET ZEND_FASTCALL ZEND_CONCAT_SPEC_CONST_CV_HANDLER(Z
 {
        USE_OPLINE
 
+       zval *op1, *op2;
 
        SAVE_OPLINE();
-       concat_function(EX_VAR(opline->result.var),
-               EX_CONSTANT(opline->op1),
-               _get_zval_ptr_cv_BP_VAR_R(execute_data, opline->op2.var));
+       op1 = EX_CONSTANT(opline->op1);
+       op2 = _get_zval_ptr_cv_BP_VAR_R(execute_data, opline->op2.var);
+
+       do {
+               if ((IS_CONST == IS_CONST || EXPECTED(Z_TYPE_P(op1) == IS_STRING)) &&
+                   (IS_CV == IS_CONST || EXPECTED(Z_TYPE_P(op2) == IS_STRING))) {
+                       zend_string *op1_str = Z_STR_P(op1);
+                       zend_string *op2_str = Z_STR_P(op2);
+                       zend_string *str;
+
+                       if (IS_CONST != IS_CONST) {
+                               if (UNEXPECTED(op1_str->len == 0)) {
+                                       ZVAL_STR_COPY(EX_VAR(opline->result.var), op2_str);
+
+                                       break;
+                               }
+                       }
+                       if (IS_CV != IS_CONST) {
+                               if (UNEXPECTED(op2_str->len == 0)) {
+                                       ZVAL_STR_COPY(EX_VAR(opline->result.var), op1_str);
 
+                                       break;
+                               }
+                       }
+                       if (IS_CONST != IS_CONST && IS_CONST != IS_CV &&
+                           !IS_INTERNED(op1_str) && GC_REFCOUNT(op1_str) == 1) {
+                           size_t len = op1_str->len;
+
+                               str = zend_string_realloc(op1_str, len + op2_str->len, 0);
+//                             memcpy(str->val, op1_str->val, op1_str->len);
+                               memcpy(str->val + len, op2_str->val, op2_str->len+1);
+                               ZVAL_NEW_STR(EX_VAR(opline->result.var), str);
+                               break;
+                       } else {
+                               str = zend_string_alloc(op1_str->len + op2_str->len, 0);
+                               memcpy(str->val, op1_str->val, op1_str->len);
+                               memcpy(str->val + op1_str->len, op2_str->val, op2_str->len+1);
+                               ZVAL_NEW_STR(EX_VAR(opline->result.var), str);
+                       }
+               } else {
+                       concat_function(EX_VAR(opline->result.var), op1, op2);
+               }
+
+       } while (0);
 
        CHECK_EXCEPTION();
        ZEND_VM_NEXT_OPCODE();
@@ -9194,16 +9298,38 @@ static ZEND_OPCODE_HANDLER_RET ZEND_FASTCALL ZEND_FAST_CONCAT_SPEC_CONST_CV_HAND
        } else {
                op2_str = zval_get_string(op2);
        }
-       str = zend_string_alloc(op1_str->len + op2_str->len, 0);
-       memcpy(str->val, op1_str->val, op1_str->len);
-       memcpy(str->val + op1_str->len, op2_str->val, op2_str->len+1);
-       ZVAL_NEW_STR(EX_VAR(opline->result.var), str);
-       if (IS_CONST != IS_CONST) {
-               zend_string_release(op1_str);
-       }
-       if (IS_CV != IS_CONST) {
-               zend_string_release(op2_str);
-       }
+       do {
+               if (IS_CONST != IS_CONST) {
+                       if (UNEXPECTED(op1_str->len == 0)) {
+                               if (IS_CV == IS_CONST) {
+                                       zend_string_addref(op2_str);
+                               }
+                               ZVAL_STR(EX_VAR(opline->result.var), op2_str);
+                               zend_string_release(op1_str);
+                               break;
+                       }
+               }
+               if (IS_CV != IS_CONST) {
+                       if (UNEXPECTED(op2_str->len == 0)) {
+                               if (IS_CONST == IS_CONST) {
+                                       zend_string_addref(op1_str);
+                               }
+                               ZVAL_STR(EX_VAR(opline->result.var), op1_str);
+                               zend_string_release(op2_str);
+                               break;
+                       }
+               }
+               str = zend_string_alloc(op1_str->len + op2_str->len, 0);
+               memcpy(str->val, op1_str->val, op1_str->len);
+               memcpy(str->val + op1_str->len, op2_str->val, op2_str->len+1);
+               ZVAL_NEW_STR(EX_VAR(opline->result.var), str);
+               if (IS_CONST != IS_CONST) {
+                       zend_string_release(op1_str);
+               }
+               if (IS_CV != IS_CONST) {
+                       zend_string_release(op2_str);
+               }
+       } while (0);
 
 
        CHECK_EXCEPTION();
@@ -10316,12 +10442,53 @@ static ZEND_OPCODE_HANDLER_RET ZEND_FASTCALL ZEND_CONCAT_SPEC_CONST_TMPVAR_HANDL
 {
        USE_OPLINE
        zend_free_op free_op2;
+       zval *op1, *op2;
 
        SAVE_OPLINE();
-       concat_function(EX_VAR(opline->result.var),
-               EX_CONSTANT(opline->op1),
-               _get_zval_ptr_var(opline->op2.var, execute_data, &free_op2));
+       op1 = EX_CONSTANT(opline->op1);
+       op2 = _get_zval_ptr_var(opline->op2.var, execute_data, &free_op2);
+
+       do {
+               if ((IS_CONST == IS_CONST || EXPECTED(Z_TYPE_P(op1) == IS_STRING)) &&
+                   ((IS_TMP_VAR|IS_VAR) == IS_CONST || EXPECTED(Z_TYPE_P(op2) == IS_STRING))) {
+                       zend_string *op1_str = Z_STR_P(op1);
+                       zend_string *op2_str = Z_STR_P(op2);
+                       zend_string *str;
+
+                       if (IS_CONST != IS_CONST) {
+                               if (UNEXPECTED(op1_str->len == 0)) {
+                                       ZVAL_STR_COPY(EX_VAR(opline->result.var), op2_str);
+
+                                       break;
+                               }
+                       }
+                       if ((IS_TMP_VAR|IS_VAR) != IS_CONST) {
+                               if (UNEXPECTED(op2_str->len == 0)) {
+                                       ZVAL_STR_COPY(EX_VAR(opline->result.var), op1_str);
+
+                                       break;
+                               }
+                       }
+                       if (IS_CONST != IS_CONST && IS_CONST != IS_CV &&
+                           !IS_INTERNED(op1_str) && GC_REFCOUNT(op1_str) == 1) {
+                           size_t len = op1_str->len;
+
+                               str = zend_string_realloc(op1_str, len + op2_str->len, 0);
+//                             memcpy(str->val, op1_str->val, op1_str->len);
+                               memcpy(str->val + len, op2_str->val, op2_str->len+1);
+                               ZVAL_NEW_STR(EX_VAR(opline->result.var), str);
+                               break;
+                       } else {
+                               str = zend_string_alloc(op1_str->len + op2_str->len, 0);
+                               memcpy(str->val, op1_str->val, op1_str->len);
+                               memcpy(str->val + op1_str->len, op2_str->val, op2_str->len+1);
+                               ZVAL_NEW_STR(EX_VAR(opline->result.var), str);
+                       }
+               } else {
+                       concat_function(EX_VAR(opline->result.var), op1, op2);
+               }
 
+       } while (0);
        zval_ptr_dtor_nogc(free_op2);
        CHECK_EXCEPTION();
        ZEND_VM_NEXT_OPCODE();
@@ -10927,16 +11094,38 @@ static ZEND_OPCODE_HANDLER_RET ZEND_FASTCALL ZEND_FAST_CONCAT_SPEC_CONST_TMPVAR_
        } else {
                op2_str = zval_get_string(op2);
        }
-       str = zend_string_alloc(op1_str->len + op2_str->len, 0);
-       memcpy(str->val, op1_str->val, op1_str->len);
-       memcpy(str->val + op1_str->len, op2_str->val, op2_str->len+1);
-       ZVAL_NEW_STR(EX_VAR(opline->result.var), str);
-       if (IS_CONST != IS_CONST) {
-               zend_string_release(op1_str);
-       }
-       if ((IS_TMP_VAR|IS_VAR) != IS_CONST) {
-               zend_string_release(op2_str);
-       }
+       do {
+               if (IS_CONST != IS_CONST) {
+                       if (UNEXPECTED(op1_str->len == 0)) {
+                               if ((IS_TMP_VAR|IS_VAR) == IS_CONST) {
+                                       zend_string_addref(op2_str);
+                               }
+                               ZVAL_STR(EX_VAR(opline->result.var), op2_str);
+                               zend_string_release(op1_str);
+                               break;
+                       }
+               }
+               if ((IS_TMP_VAR|IS_VAR) != IS_CONST) {
+                       if (UNEXPECTED(op2_str->len == 0)) {
+                               if (IS_CONST == IS_CONST) {
+                                       zend_string_addref(op1_str);
+                               }
+                               ZVAL_STR(EX_VAR(opline->result.var), op1_str);
+                               zend_string_release(op2_str);
+                               break;
+                       }
+               }
+               str = zend_string_alloc(op1_str->len + op2_str->len, 0);
+               memcpy(str->val, op1_str->val, op1_str->len);
+               memcpy(str->val + op1_str->len, op2_str->val, op2_str->len+1);
+               ZVAL_NEW_STR(EX_VAR(opline->result.var), str);
+               if (IS_CONST != IS_CONST) {
+                       zend_string_release(op1_str);
+               }
+               if ((IS_TMP_VAR|IS_VAR) != IS_CONST) {
+                       zend_string_release(op2_str);
+               }
+       } while (0);
 
        zval_ptr_dtor_nogc(free_op2);
        CHECK_EXCEPTION();
@@ -30317,12 +30506,53 @@ static ZEND_OPCODE_HANDLER_RET ZEND_FASTCALL ZEND_CONCAT_SPEC_CV_CONST_HANDLER(Z
 {
        USE_OPLINE
 
+       zval *op1, *op2;
 
        SAVE_OPLINE();
-       concat_function(EX_VAR(opline->result.var),
-               _get_zval_ptr_cv_BP_VAR_R(execute_data, opline->op1.var),
-               EX_CONSTANT(opline->op2));
+       op1 = _get_zval_ptr_cv_BP_VAR_R(execute_data, opline->op1.var);
+       op2 = EX_CONSTANT(opline->op2);
+
+       do {
+               if ((IS_CV == IS_CONST || EXPECTED(Z_TYPE_P(op1) == IS_STRING)) &&
+                   (IS_CONST == IS_CONST || EXPECTED(Z_TYPE_P(op2) == IS_STRING))) {
+                       zend_string *op1_str = Z_STR_P(op1);
+                       zend_string *op2_str = Z_STR_P(op2);
+                       zend_string *str;
+
+                       if (IS_CV != IS_CONST) {
+                               if (UNEXPECTED(op1_str->len == 0)) {
+                                       ZVAL_STR_COPY(EX_VAR(opline->result.var), op2_str);
+
+                                       break;
+                               }
+                       }
+                       if (IS_CONST != IS_CONST) {
+                               if (UNEXPECTED(op2_str->len == 0)) {
+                                       ZVAL_STR_COPY(EX_VAR(opline->result.var), op1_str);
+
+                                       break;
+                               }
+                       }
+                       if (IS_CV != IS_CONST && IS_CV != IS_CV &&
+                           !IS_INTERNED(op1_str) && GC_REFCOUNT(op1_str) == 1) {
+                           size_t len = op1_str->len;
+
+                               str = zend_string_realloc(op1_str, len + op2_str->len, 0);
+//                             memcpy(str->val, op1_str->val, op1_str->len);
+                               memcpy(str->val + len, op2_str->val, op2_str->len+1);
+                               ZVAL_NEW_STR(EX_VAR(opline->result.var), str);
+                               break;
+                       } else {
+                               str = zend_string_alloc(op1_str->len + op2_str->len, 0);
+                               memcpy(str->val, op1_str->val, op1_str->len);
+                               memcpy(str->val + op1_str->len, op2_str->val, op2_str->len+1);
+                               ZVAL_NEW_STR(EX_VAR(opline->result.var), str);
+                       }
+               } else {
+                       concat_function(EX_VAR(opline->result.var), op1, op2);
+               }
 
+       } while (0);
 
        CHECK_EXCEPTION();
        ZEND_VM_NEXT_OPCODE();
@@ -32168,16 +32398,38 @@ static ZEND_OPCODE_HANDLER_RET ZEND_FASTCALL ZEND_FAST_CONCAT_SPEC_CV_CONST_HAND
        } else {
                op2_str = zval_get_string(op2);
        }
-       str = zend_string_alloc(op1_str->len + op2_str->len, 0);
-       memcpy(str->val, op1_str->val, op1_str->len);
-       memcpy(str->val + op1_str->len, op2_str->val, op2_str->len+1);
-       ZVAL_NEW_STR(EX_VAR(opline->result.var), str);
-       if (IS_CV != IS_CONST) {
-               zend_string_release(op1_str);
-       }
-       if (IS_CONST != IS_CONST) {
-               zend_string_release(op2_str);
-       }
+       do {
+               if (IS_CV != IS_CONST) {
+                       if (UNEXPECTED(op1_str->len == 0)) {
+                               if (IS_CONST == IS_CONST) {
+                                       zend_string_addref(op2_str);
+                               }
+                               ZVAL_STR(EX_VAR(opline->result.var), op2_str);
+                               zend_string_release(op1_str);
+                               break;
+                       }
+               }
+               if (IS_CONST != IS_CONST) {
+                       if (UNEXPECTED(op2_str->len == 0)) {
+                               if (IS_CV == IS_CONST) {
+                                       zend_string_addref(op1_str);
+                               }
+                               ZVAL_STR(EX_VAR(opline->result.var), op1_str);
+                               zend_string_release(op2_str);
+                               break;
+                       }
+               }
+               str = zend_string_alloc(op1_str->len + op2_str->len, 0);
+               memcpy(str->val, op1_str->val, op1_str->len);
+               memcpy(str->val + op1_str->len, op2_str->val, op2_str->len+1);
+               ZVAL_NEW_STR(EX_VAR(opline->result.var), str);
+               if (IS_CV != IS_CONST) {
+                       zend_string_release(op1_str);
+               }
+               if (IS_CONST != IS_CONST) {
+                       zend_string_release(op2_str);
+               }
+       } while (0);
 
 
        CHECK_EXCEPTION();
@@ -35573,12 +35825,53 @@ static ZEND_OPCODE_HANDLER_RET ZEND_FASTCALL ZEND_CONCAT_SPEC_CV_CV_HANDLER(ZEND
 {
        USE_OPLINE
 
+       zval *op1, *op2;
 
        SAVE_OPLINE();
-       concat_function(EX_VAR(opline->result.var),
-               _get_zval_ptr_cv_BP_VAR_R(execute_data, opline->op1.var),
-               _get_zval_ptr_cv_BP_VAR_R(execute_data, opline->op2.var));
+       op1 = _get_zval_ptr_cv_BP_VAR_R(execute_data, opline->op1.var);
+       op2 = _get_zval_ptr_cv_BP_VAR_R(execute_data, opline->op2.var);
+
+       do {
+               if ((IS_CV == IS_CONST || EXPECTED(Z_TYPE_P(op1) == IS_STRING)) &&
+                   (IS_CV == IS_CONST || EXPECTED(Z_TYPE_P(op2) == IS_STRING))) {
+                       zend_string *op1_str = Z_STR_P(op1);
+                       zend_string *op2_str = Z_STR_P(op2);
+                       zend_string *str;
+
+                       if (IS_CV != IS_CONST) {
+                               if (UNEXPECTED(op1_str->len == 0)) {
+                                       ZVAL_STR_COPY(EX_VAR(opline->result.var), op2_str);
+
+                                       break;
+                               }
+                       }
+                       if (IS_CV != IS_CONST) {
+                               if (UNEXPECTED(op2_str->len == 0)) {
+                                       ZVAL_STR_COPY(EX_VAR(opline->result.var), op1_str);
 
+                                       break;
+                               }
+                       }
+                       if (IS_CV != IS_CONST && IS_CV != IS_CV &&
+                           !IS_INTERNED(op1_str) && GC_REFCOUNT(op1_str) == 1) {
+                           size_t len = op1_str->len;
+
+                               str = zend_string_realloc(op1_str, len + op2_str->len, 0);
+//                             memcpy(str->val, op1_str->val, op1_str->len);
+                               memcpy(str->val + len, op2_str->val, op2_str->len+1);
+                               ZVAL_NEW_STR(EX_VAR(opline->result.var), str);
+                               break;
+                       } else {
+                               str = zend_string_alloc(op1_str->len + op2_str->len, 0);
+                               memcpy(str->val, op1_str->val, op1_str->len);
+                               memcpy(str->val + op1_str->len, op2_str->val, op2_str->len+1);
+                               ZVAL_NEW_STR(EX_VAR(opline->result.var), str);
+                       }
+               } else {
+                       concat_function(EX_VAR(opline->result.var), op1, op2);
+               }
+
+       } while (0);
 
        CHECK_EXCEPTION();
        ZEND_VM_NEXT_OPCODE();
@@ -37261,16 +37554,38 @@ static ZEND_OPCODE_HANDLER_RET ZEND_FASTCALL ZEND_FAST_CONCAT_SPEC_CV_CV_HANDLER
        } else {
                op2_str = zval_get_string(op2);
        }
-       str = zend_string_alloc(op1_str->len + op2_str->len, 0);
-       memcpy(str->val, op1_str->val, op1_str->len);
-       memcpy(str->val + op1_str->len, op2_str->val, op2_str->len+1);
-       ZVAL_NEW_STR(EX_VAR(opline->result.var), str);
-       if (IS_CV != IS_CONST) {
-               zend_string_release(op1_str);
-       }
-       if (IS_CV != IS_CONST) {
-               zend_string_release(op2_str);
-       }
+       do {
+               if (IS_CV != IS_CONST) {
+                       if (UNEXPECTED(op1_str->len == 0)) {
+                               if (IS_CV == IS_CONST) {
+                                       zend_string_addref(op2_str);
+                               }
+                               ZVAL_STR(EX_VAR(opline->result.var), op2_str);
+                               zend_string_release(op1_str);
+                               break;
+                       }
+               }
+               if (IS_CV != IS_CONST) {
+                       if (UNEXPECTED(op2_str->len == 0)) {
+                               if (IS_CV == IS_CONST) {
+                                       zend_string_addref(op1_str);
+                               }
+                               ZVAL_STR(EX_VAR(opline->result.var), op1_str);
+                               zend_string_release(op2_str);
+                               break;
+                       }
+               }
+               str = zend_string_alloc(op1_str->len + op2_str->len, 0);
+               memcpy(str->val, op1_str->val, op1_str->len);
+               memcpy(str->val + op1_str->len, op2_str->val, op2_str->len+1);
+               ZVAL_NEW_STR(EX_VAR(opline->result.var), str);
+               if (IS_CV != IS_CONST) {
+                       zend_string_release(op1_str);
+               }
+               if (IS_CV != IS_CONST) {
+                       zend_string_release(op2_str);
+               }
+       } while (0);
 
 
        CHECK_EXCEPTION();
@@ -38286,12 +38601,53 @@ static ZEND_OPCODE_HANDLER_RET ZEND_FASTCALL ZEND_CONCAT_SPEC_CV_TMPVAR_HANDLER(
 {
        USE_OPLINE
        zend_free_op free_op2;
+       zval *op1, *op2;
 
        SAVE_OPLINE();
-       concat_function(EX_VAR(opline->result.var),
-               _get_zval_ptr_cv_BP_VAR_R(execute_data, opline->op1.var),
-               _get_zval_ptr_var(opline->op2.var, execute_data, &free_op2));
+       op1 = _get_zval_ptr_cv_BP_VAR_R(execute_data, opline->op1.var);
+       op2 = _get_zval_ptr_var(opline->op2.var, execute_data, &free_op2);
 
+       do {
+               if ((IS_CV == IS_CONST || EXPECTED(Z_TYPE_P(op1) == IS_STRING)) &&
+                   ((IS_TMP_VAR|IS_VAR) == IS_CONST || EXPECTED(Z_TYPE_P(op2) == IS_STRING))) {
+                       zend_string *op1_str = Z_STR_P(op1);
+                       zend_string *op2_str = Z_STR_P(op2);
+                       zend_string *str;
+
+                       if (IS_CV != IS_CONST) {
+                               if (UNEXPECTED(op1_str->len == 0)) {
+                                       ZVAL_STR_COPY(EX_VAR(opline->result.var), op2_str);
+
+                                       break;
+                               }
+                       }
+                       if ((IS_TMP_VAR|IS_VAR) != IS_CONST) {
+                               if (UNEXPECTED(op2_str->len == 0)) {
+                                       ZVAL_STR_COPY(EX_VAR(opline->result.var), op1_str);
+
+                                       break;
+                               }
+                       }
+                       if (IS_CV != IS_CONST && IS_CV != IS_CV &&
+                           !IS_INTERNED(op1_str) && GC_REFCOUNT(op1_str) == 1) {
+                           size_t len = op1_str->len;
+
+                               str = zend_string_realloc(op1_str, len + op2_str->len, 0);
+//                             memcpy(str->val, op1_str->val, op1_str->len);
+                               memcpy(str->val + len, op2_str->val, op2_str->len+1);
+                               ZVAL_NEW_STR(EX_VAR(opline->result.var), str);
+                               break;
+                       } else {
+                               str = zend_string_alloc(op1_str->len + op2_str->len, 0);
+                               memcpy(str->val, op1_str->val, op1_str->len);
+                               memcpy(str->val + op1_str->len, op2_str->val, op2_str->len+1);
+                               ZVAL_NEW_STR(EX_VAR(opline->result.var), str);
+                       }
+               } else {
+                       concat_function(EX_VAR(opline->result.var), op1, op2);
+               }
+
+       } while (0);
        zval_ptr_dtor_nogc(free_op2);
        CHECK_EXCEPTION();
        ZEND_VM_NEXT_OPCODE();
@@ -39849,16 +40205,38 @@ static ZEND_OPCODE_HANDLER_RET ZEND_FASTCALL ZEND_FAST_CONCAT_SPEC_CV_TMPVAR_HAN
        } else {
                op2_str = zval_get_string(op2);
        }
-       str = zend_string_alloc(op1_str->len + op2_str->len, 0);
-       memcpy(str->val, op1_str->val, op1_str->len);
-       memcpy(str->val + op1_str->len, op2_str->val, op2_str->len+1);
-       ZVAL_NEW_STR(EX_VAR(opline->result.var), str);
-       if (IS_CV != IS_CONST) {
-               zend_string_release(op1_str);
-       }
-       if ((IS_TMP_VAR|IS_VAR) != IS_CONST) {
-               zend_string_release(op2_str);
-       }
+       do {
+               if (IS_CV != IS_CONST) {
+                       if (UNEXPECTED(op1_str->len == 0)) {
+                               if ((IS_TMP_VAR|IS_VAR) == IS_CONST) {
+                                       zend_string_addref(op2_str);
+                               }
+                               ZVAL_STR(EX_VAR(opline->result.var), op2_str);
+                               zend_string_release(op1_str);
+                               break;
+                       }
+               }
+               if ((IS_TMP_VAR|IS_VAR) != IS_CONST) {
+                       if (UNEXPECTED(op2_str->len == 0)) {
+                               if (IS_CV == IS_CONST) {
+                                       zend_string_addref(op1_str);
+                               }
+                               ZVAL_STR(EX_VAR(opline->result.var), op1_str);
+                               zend_string_release(op2_str);
+                               break;
+                       }
+               }
+               str = zend_string_alloc(op1_str->len + op2_str->len, 0);
+               memcpy(str->val, op1_str->val, op1_str->len);
+               memcpy(str->val + op1_str->len, op2_str->val, op2_str->len+1);
+               ZVAL_NEW_STR(EX_VAR(opline->result.var), str);
+               if (IS_CV != IS_CONST) {
+                       zend_string_release(op1_str);
+               }
+               if ((IS_TMP_VAR|IS_VAR) != IS_CONST) {
+                       zend_string_release(op2_str);
+               }
+       } while (0);
 
        zval_ptr_dtor_nogc(free_op2);
        CHECK_EXCEPTION();
@@ -41333,12 +41711,53 @@ static ZEND_OPCODE_HANDLER_RET ZEND_FASTCALL ZEND_CONCAT_SPEC_TMPVAR_CONST_HANDL
 {
        USE_OPLINE
        zend_free_op free_op1;
+       zval *op1, *op2;
 
        SAVE_OPLINE();
-       concat_function(EX_VAR(opline->result.var),
-               _get_zval_ptr_var(opline->op1.var, execute_data, &free_op1),
-               EX_CONSTANT(opline->op2));
-       zval_ptr_dtor_nogc(free_op1);
+       op1 = _get_zval_ptr_var(opline->op1.var, execute_data, &free_op1);
+       op2 = EX_CONSTANT(opline->op2);
+
+       do {
+               if (((IS_TMP_VAR|IS_VAR) == IS_CONST || EXPECTED(Z_TYPE_P(op1) == IS_STRING)) &&
+                   (IS_CONST == IS_CONST || EXPECTED(Z_TYPE_P(op2) == IS_STRING))) {
+                       zend_string *op1_str = Z_STR_P(op1);
+                       zend_string *op2_str = Z_STR_P(op2);
+                       zend_string *str;
+
+                       if ((IS_TMP_VAR|IS_VAR) != IS_CONST) {
+                               if (UNEXPECTED(op1_str->len == 0)) {
+                                       ZVAL_STR_COPY(EX_VAR(opline->result.var), op2_str);
+                                       zval_ptr_dtor_nogc(free_op1);
+                                       break;
+                               }
+                       }
+                       if (IS_CONST != IS_CONST) {
+                               if (UNEXPECTED(op2_str->len == 0)) {
+                                       ZVAL_STR_COPY(EX_VAR(opline->result.var), op1_str);
+                                       zval_ptr_dtor_nogc(free_op1);
+                                       break;
+                               }
+                       }
+                       if ((IS_TMP_VAR|IS_VAR) != IS_CONST && (IS_TMP_VAR|IS_VAR) != IS_CV &&
+                           !IS_INTERNED(op1_str) && GC_REFCOUNT(op1_str) == 1) {
+                           size_t len = op1_str->len;
+
+                               str = zend_string_realloc(op1_str, len + op2_str->len, 0);
+//                             memcpy(str->val, op1_str->val, op1_str->len);
+                               memcpy(str->val + len, op2_str->val, op2_str->len+1);
+                               ZVAL_NEW_STR(EX_VAR(opline->result.var), str);
+                               break;
+                       } else {
+                               str = zend_string_alloc(op1_str->len + op2_str->len, 0);
+                               memcpy(str->val, op1_str->val, op1_str->len);
+                               memcpy(str->val + op1_str->len, op2_str->val, op2_str->len+1);
+                               ZVAL_NEW_STR(EX_VAR(opline->result.var), str);
+                       }
+               } else {
+                       concat_function(EX_VAR(opline->result.var), op1, op2);
+               }
+               zval_ptr_dtor_nogc(free_op1);
+       } while (0);
 
        CHECK_EXCEPTION();
        ZEND_VM_NEXT_OPCODE();
@@ -42008,16 +42427,38 @@ static ZEND_OPCODE_HANDLER_RET ZEND_FASTCALL ZEND_FAST_CONCAT_SPEC_TMPVAR_CONST_
        } else {
                op2_str = zval_get_string(op2);
        }
-       str = zend_string_alloc(op1_str->len + op2_str->len, 0);
-       memcpy(str->val, op1_str->val, op1_str->len);
-       memcpy(str->val + op1_str->len, op2_str->val, op2_str->len+1);
-       ZVAL_NEW_STR(EX_VAR(opline->result.var), str);
-       if ((IS_TMP_VAR|IS_VAR) != IS_CONST) {
-               zend_string_release(op1_str);
-       }
-       if (IS_CONST != IS_CONST) {
-               zend_string_release(op2_str);
-       }
+       do {
+               if ((IS_TMP_VAR|IS_VAR) != IS_CONST) {
+                       if (UNEXPECTED(op1_str->len == 0)) {
+                               if (IS_CONST == IS_CONST) {
+                                       zend_string_addref(op2_str);
+                               }
+                               ZVAL_STR(EX_VAR(opline->result.var), op2_str);
+                               zend_string_release(op1_str);
+                               break;
+                       }
+               }
+               if (IS_CONST != IS_CONST) {
+                       if (UNEXPECTED(op2_str->len == 0)) {
+                               if ((IS_TMP_VAR|IS_VAR) == IS_CONST) {
+                                       zend_string_addref(op1_str);
+                               }
+                               ZVAL_STR(EX_VAR(opline->result.var), op1_str);
+                               zend_string_release(op2_str);
+                               break;
+                       }
+               }
+               str = zend_string_alloc(op1_str->len + op2_str->len, 0);
+               memcpy(str->val, op1_str->val, op1_str->len);
+               memcpy(str->val + op1_str->len, op2_str->val, op2_str->len+1);
+               ZVAL_NEW_STR(EX_VAR(opline->result.var), str);
+               if ((IS_TMP_VAR|IS_VAR) != IS_CONST) {
+                       zend_string_release(op1_str);
+               }
+               if (IS_CONST != IS_CONST) {
+                       zend_string_release(op2_str);
+               }
+       } while (0);
        zval_ptr_dtor_nogc(free_op1);
 
        CHECK_EXCEPTION();
@@ -43636,12 +44077,53 @@ static ZEND_OPCODE_HANDLER_RET ZEND_FASTCALL ZEND_CONCAT_SPEC_TMPVAR_CV_HANDLER(
 {
        USE_OPLINE
        zend_free_op free_op1;
+       zval *op1, *op2;
 
        SAVE_OPLINE();
-       concat_function(EX_VAR(opline->result.var),
-               _get_zval_ptr_var(opline->op1.var, execute_data, &free_op1),
-               _get_zval_ptr_cv_BP_VAR_R(execute_data, opline->op2.var));
-       zval_ptr_dtor_nogc(free_op1);
+       op1 = _get_zval_ptr_var(opline->op1.var, execute_data, &free_op1);
+       op2 = _get_zval_ptr_cv_BP_VAR_R(execute_data, opline->op2.var);
+
+       do {
+               if (((IS_TMP_VAR|IS_VAR) == IS_CONST || EXPECTED(Z_TYPE_P(op1) == IS_STRING)) &&
+                   (IS_CV == IS_CONST || EXPECTED(Z_TYPE_P(op2) == IS_STRING))) {
+                       zend_string *op1_str = Z_STR_P(op1);
+                       zend_string *op2_str = Z_STR_P(op2);
+                       zend_string *str;
+
+                       if ((IS_TMP_VAR|IS_VAR) != IS_CONST) {
+                               if (UNEXPECTED(op1_str->len == 0)) {
+                                       ZVAL_STR_COPY(EX_VAR(opline->result.var), op2_str);
+                                       zval_ptr_dtor_nogc(free_op1);
+                                       break;
+                               }
+                       }
+                       if (IS_CV != IS_CONST) {
+                               if (UNEXPECTED(op2_str->len == 0)) {
+                                       ZVAL_STR_COPY(EX_VAR(opline->result.var), op1_str);
+                                       zval_ptr_dtor_nogc(free_op1);
+                                       break;
+                               }
+                       }
+                       if ((IS_TMP_VAR|IS_VAR) != IS_CONST && (IS_TMP_VAR|IS_VAR) != IS_CV &&
+                           !IS_INTERNED(op1_str) && GC_REFCOUNT(op1_str) == 1) {
+                           size_t len = op1_str->len;
+
+                               str = zend_string_realloc(op1_str, len + op2_str->len, 0);
+//                             memcpy(str->val, op1_str->val, op1_str->len);
+                               memcpy(str->val + len, op2_str->val, op2_str->len+1);
+                               ZVAL_NEW_STR(EX_VAR(opline->result.var), str);
+                               break;
+                       } else {
+                               str = zend_string_alloc(op1_str->len + op2_str->len, 0);
+                               memcpy(str->val, op1_str->val, op1_str->len);
+                               memcpy(str->val + op1_str->len, op2_str->val, op2_str->len+1);
+                               ZVAL_NEW_STR(EX_VAR(opline->result.var), str);
+                       }
+               } else {
+                       concat_function(EX_VAR(opline->result.var), op1, op2);
+               }
+               zval_ptr_dtor_nogc(free_op1);
+       } while (0);
 
        CHECK_EXCEPTION();
        ZEND_VM_NEXT_OPCODE();
@@ -44085,16 +44567,38 @@ static ZEND_OPCODE_HANDLER_RET ZEND_FASTCALL ZEND_FAST_CONCAT_SPEC_TMPVAR_CV_HAN
        } else {
                op2_str = zval_get_string(op2);
        }
-       str = zend_string_alloc(op1_str->len + op2_str->len, 0);
-       memcpy(str->val, op1_str->val, op1_str->len);
-       memcpy(str->val + op1_str->len, op2_str->val, op2_str->len+1);
-       ZVAL_NEW_STR(EX_VAR(opline->result.var), str);
-       if ((IS_TMP_VAR|IS_VAR) != IS_CONST) {
-               zend_string_release(op1_str);
-       }
-       if (IS_CV != IS_CONST) {
-               zend_string_release(op2_str);
-       }
+       do {
+               if ((IS_TMP_VAR|IS_VAR) != IS_CONST) {
+                       if (UNEXPECTED(op1_str->len == 0)) {
+                               if (IS_CV == IS_CONST) {
+                                       zend_string_addref(op2_str);
+                               }
+                               ZVAL_STR(EX_VAR(opline->result.var), op2_str);
+                               zend_string_release(op1_str);
+                               break;
+                       }
+               }
+               if (IS_CV != IS_CONST) {
+                       if (UNEXPECTED(op2_str->len == 0)) {
+                               if ((IS_TMP_VAR|IS_VAR) == IS_CONST) {
+                                       zend_string_addref(op1_str);
+                               }
+                               ZVAL_STR(EX_VAR(opline->result.var), op1_str);
+                               zend_string_release(op2_str);
+                               break;
+                       }
+               }
+               str = zend_string_alloc(op1_str->len + op2_str->len, 0);
+               memcpy(str->val, op1_str->val, op1_str->len);
+               memcpy(str->val + op1_str->len, op2_str->val, op2_str->len+1);
+               ZVAL_NEW_STR(EX_VAR(opline->result.var), str);
+               if ((IS_TMP_VAR|IS_VAR) != IS_CONST) {
+                       zend_string_release(op1_str);
+               }
+               if (IS_CV != IS_CONST) {
+                       zend_string_release(op2_str);
+               }
+       } while (0);
        zval_ptr_dtor_nogc(free_op1);
 
        CHECK_EXCEPTION();
@@ -44700,12 +45204,53 @@ static ZEND_OPCODE_HANDLER_RET ZEND_FASTCALL ZEND_CONCAT_SPEC_TMPVAR_TMPVAR_HAND
 {
        USE_OPLINE
        zend_free_op free_op1, free_op2;
+       zval *op1, *op2;
 
        SAVE_OPLINE();
-       concat_function(EX_VAR(opline->result.var),
-               _get_zval_ptr_var(opline->op1.var, execute_data, &free_op1),
-               _get_zval_ptr_var(opline->op2.var, execute_data, &free_op2));
-       zval_ptr_dtor_nogc(free_op1);
+       op1 = _get_zval_ptr_var(opline->op1.var, execute_data, &free_op1);
+       op2 = _get_zval_ptr_var(opline->op2.var, execute_data, &free_op2);
+
+       do {
+               if (((IS_TMP_VAR|IS_VAR) == IS_CONST || EXPECTED(Z_TYPE_P(op1) == IS_STRING)) &&
+                   ((IS_TMP_VAR|IS_VAR) == IS_CONST || EXPECTED(Z_TYPE_P(op2) == IS_STRING))) {
+                       zend_string *op1_str = Z_STR_P(op1);
+                       zend_string *op2_str = Z_STR_P(op2);
+                       zend_string *str;
+
+                       if ((IS_TMP_VAR|IS_VAR) != IS_CONST) {
+                               if (UNEXPECTED(op1_str->len == 0)) {
+                                       ZVAL_STR_COPY(EX_VAR(opline->result.var), op2_str);
+                                       zval_ptr_dtor_nogc(free_op1);
+                                       break;
+                               }
+                       }
+                       if ((IS_TMP_VAR|IS_VAR) != IS_CONST) {
+                               if (UNEXPECTED(op2_str->len == 0)) {
+                                       ZVAL_STR_COPY(EX_VAR(opline->result.var), op1_str);
+                                       zval_ptr_dtor_nogc(free_op1);
+                                       break;
+                               }
+                       }
+                       if ((IS_TMP_VAR|IS_VAR) != IS_CONST && (IS_TMP_VAR|IS_VAR) != IS_CV &&
+                           !IS_INTERNED(op1_str) && GC_REFCOUNT(op1_str) == 1) {
+                           size_t len = op1_str->len;
+
+                               str = zend_string_realloc(op1_str, len + op2_str->len, 0);
+//                             memcpy(str->val, op1_str->val, op1_str->len);
+                               memcpy(str->val + len, op2_str->val, op2_str->len+1);
+                               ZVAL_NEW_STR(EX_VAR(opline->result.var), str);
+                               break;
+                       } else {
+                               str = zend_string_alloc(op1_str->len + op2_str->len, 0);
+                               memcpy(str->val, op1_str->val, op1_str->len);
+                               memcpy(str->val + op1_str->len, op2_str->val, op2_str->len+1);
+                               ZVAL_NEW_STR(EX_VAR(opline->result.var), str);
+                       }
+               } else {
+                       concat_function(EX_VAR(opline->result.var), op1, op2);
+               }
+               zval_ptr_dtor_nogc(free_op1);
+       } while (0);
        zval_ptr_dtor_nogc(free_op2);
        CHECK_EXCEPTION();
        ZEND_VM_NEXT_OPCODE();
@@ -45150,16 +45695,38 @@ static ZEND_OPCODE_HANDLER_RET ZEND_FASTCALL ZEND_FAST_CONCAT_SPEC_TMPVAR_TMPVAR
        } else {
                op2_str = zval_get_string(op2);
        }
-       str = zend_string_alloc(op1_str->len + op2_str->len, 0);
-       memcpy(str->val, op1_str->val, op1_str->len);
-       memcpy(str->val + op1_str->len, op2_str->val, op2_str->len+1);
-       ZVAL_NEW_STR(EX_VAR(opline->result.var), str);
-       if ((IS_TMP_VAR|IS_VAR) != IS_CONST) {
-               zend_string_release(op1_str);
-       }
-       if ((IS_TMP_VAR|IS_VAR) != IS_CONST) {
-               zend_string_release(op2_str);
-       }
+       do {
+               if ((IS_TMP_VAR|IS_VAR) != IS_CONST) {
+                       if (UNEXPECTED(op1_str->len == 0)) {
+                               if ((IS_TMP_VAR|IS_VAR) == IS_CONST) {
+                                       zend_string_addref(op2_str);
+                               }
+                               ZVAL_STR(EX_VAR(opline->result.var), op2_str);
+                               zend_string_release(op1_str);
+                               break;
+                       }
+               }
+               if ((IS_TMP_VAR|IS_VAR) != IS_CONST) {
+                       if (UNEXPECTED(op2_str->len == 0)) {
+                               if ((IS_TMP_VAR|IS_VAR) == IS_CONST) {
+                                       zend_string_addref(op1_str);
+                               }
+                               ZVAL_STR(EX_VAR(opline->result.var), op1_str);
+                               zend_string_release(op2_str);
+                               break;
+                       }
+               }
+               str = zend_string_alloc(op1_str->len + op2_str->len, 0);
+               memcpy(str->val, op1_str->val, op1_str->len);
+               memcpy(str->val + op1_str->len, op2_str->val, op2_str->len+1);
+               ZVAL_NEW_STR(EX_VAR(opline->result.var), str);
+               if ((IS_TMP_VAR|IS_VAR) != IS_CONST) {
+                       zend_string_release(op1_str);
+               }
+               if ((IS_TMP_VAR|IS_VAR) != IS_CONST) {
+                       zend_string_release(op2_str);
+               }
+       } while (0);
        zval_ptr_dtor_nogc(free_op1);
        zval_ptr_dtor_nogc(free_op2);
        CHECK_EXCEPTION();