diff --git a/ext/opcache/jit/zend_jit_arm64.dasc b/ext/opcache/jit/zend_jit_arm64.dasc index 1315eefd6ec..861972671d4 100644 --- a/ext/opcache/jit/zend_jit_arm64.dasc +++ b/ext/opcache/jit/zend_jit_arm64.dasc @@ -4804,12 +4804,14 @@ static int zend_jit_concat_helper(dasm_State **Dst, } | LOAD_ZVAL_ADDR FCARG2x, op1_addr | LOAD_ZVAL_ADDR CARG3, op2_addr - | EXT_CALL zend_jit_fast_concat_helper, REG0 + if (op1_type == IS_CV || op1_type == IS_CONST) { + | EXT_CALL zend_jit_fast_concat_helper, REG0 + } else { + | EXT_CALL zend_jit_fast_concat_tmp_helper, REG0 + } } /* concatination with empty string may increase refcount */ - op1_info |= MAY_BE_RCN; op2_info |= MAY_BE_RCN; - | FREE_OP op1_type, op1, op1_info, 0, opline, ZREG_TMP1, ZREG_TMP2 | FREE_OP op2_type, op2, op2_info, 0, opline, ZREG_TMP1, ZREG_TMP2 |5: } diff --git a/ext/opcache/jit/zend_jit_disasm.c b/ext/opcache/jit/zend_jit_disasm.c index 5971954cd54..c10df623e23 100644 --- a/ext/opcache/jit/zend_jit_disasm.c +++ b/ext/opcache/jit/zend_jit_disasm.c @@ -637,6 +637,7 @@ static int zend_jit_disasm_init(void) REGISTER_HELPER(zend_jit_assign_dim_op_helper); REGISTER_HELPER(zend_jit_fast_assign_concat_helper); REGISTER_HELPER(zend_jit_fast_concat_helper); + REGISTER_HELPER(zend_jit_fast_concat_tmp_helper); REGISTER_HELPER(zend_jit_isset_dim_helper); REGISTER_HELPER(zend_jit_free_call_frame); REGISTER_HELPER(zend_jit_fetch_global_helper); diff --git a/ext/opcache/jit/zend_jit_helpers.c b/ext/opcache/jit/zend_jit_helpers.c index d4be2768371..77142d70ffd 100644 --- a/ext/opcache/jit/zend_jit_helpers.c +++ b/ext/opcache/jit/zend_jit_helpers.c @@ -1265,6 +1265,40 @@ static void ZEND_FASTCALL zend_jit_fast_concat_helper(zval *result, zval *op1, z ZSTR_VAL(result_str)[result_len] = '\0'; } +static void ZEND_FASTCALL zend_jit_fast_concat_tmp_helper(zval *result, zval *op1, zval *op2) +{ + zend_string *op1_str = Z_STR_P(op1); + size_t op1_len = ZSTR_LEN(op1_str); + size_t op2_len = Z_STRLEN_P(op2); + size_t result_len = op1_len + op2_len; + zend_string *result_str; + + if (UNEXPECTED(op1_len > SIZE_MAX - op2_len)) { + zend_throw_error(NULL, "String size overflow"); + return; + } + + do { + if (!ZSTR_IS_INTERNED(op1_str)) { + if (GC_REFCOUNT(op1_str) == 1) { + Z_STR_P(op1) = result_str = + perealloc(op1_str, ZEND_MM_ALIGNED_SIZE(_ZSTR_STRUCT_SIZE(result_len)), 0); + ZSTR_LEN(result_str) = result_len; + zend_string_forget_hash_val(result_str); + break; + } + GC_DELREF(op1_str); + } + result_str = zend_string_alloc(result_len, 0); + memcpy(ZSTR_VAL(result_str), ZSTR_VAL(op1_str), op1_len); + } while (0); + + ZVAL_NEW_STR(result, result_str); + + memcpy(ZSTR_VAL(result_str) + op1_len, Z_STRVAL_P(op2), op2_len); + ZSTR_VAL(result_str)[result_len] = '\0'; +} + static int ZEND_FASTCALL zend_jit_isset_dim_helper(zval *container, zval *offset) { if (UNEXPECTED(Z_TYPE_P(offset) == IS_UNDEF)) { diff --git a/ext/opcache/jit/zend_jit_x86.dasc b/ext/opcache/jit/zend_jit_x86.dasc index 8d3fcda3c20..b580e48b30c 100644 --- a/ext/opcache/jit/zend_jit_x86.dasc +++ b/ext/opcache/jit/zend_jit_x86.dasc @@ -5251,15 +5251,17 @@ static int zend_jit_concat_helper(dasm_State **Dst, | sub r4, 12 | PUSH_ZVAL_ADDR op2_addr, r0 |.endif - | EXT_CALL zend_jit_fast_concat_helper, r0 + if (op1_type == IS_CV || op1_type == IS_CONST) { + | EXT_CALL zend_jit_fast_concat_helper, r0 + } else { + | EXT_CALL zend_jit_fast_concat_tmp_helper, r0 + } |.if not(X64) | add r4, 12 |.endif } /* concatination with empty string may increase refcount */ - op1_info |= MAY_BE_RCN; op2_info |= MAY_BE_RCN; - | FREE_OP op1_type, op1, op1_info, 0, opline | FREE_OP op2_type, op2, op2_info, 0, opline |5: }