URL: http://github.com/ndossche/php-src/pull/12.patch
mizer/zend_dfg.c b/Zend/Optimizer/zend_dfg.c index 2207b594b85a5..73cc205cd5374 100644 --- a/Zend/Optimizer/zend_dfg.c +++ b/Zend/Optimizer/zend_dfg.c @@ -174,6 +174,10 @@ static zend_always_inline void _zend_dfg_add_use_def_op(const zend_op_array *op_ } break; case ZEND_SEND_VAR: + if (opline->op1_type == IS_CV && ((build_flags & ZEND_SSA_RC_INFERENCE) || opline->op2_type == IS_UNUSED)) { + goto add_op1_def; + } + break; case ZEND_CAST: case ZEND_QM_ASSIGN: case ZEND_JMP_SET: diff --git a/Zend/Optimizer/zend_inference.c b/Zend/Optimizer/zend_inference.c index 944283af71abc..2cb491efa5f3d 100644 --- a/Zend/Optimizer/zend_inference.c +++ b/Zend/Optimizer/zend_inference.c @@ -2950,6 +2950,10 @@ static zend_always_inline zend_result _zend_update_type_info( if (t1 & (MAY_BE_RC1|MAY_BE_REF)) { tmp |= MAY_BE_RCN; } + if ((t1 & (MAY_BE_ARRAY|MAY_BE_STRING)) && (t1 & MAY_BE_RC1) && !(t1 & (MAY_BE_UNDEF|MAY_BE_REF)) && ssa_vars[ssa_op->op1_def].no_val && !ssa_vars[ssa_op->op1_def].alias) { + /* implicit move may make value undef */ + tmp |= MAY_BE_UNDEF; + } UPDATE_SSA_TYPE(tmp, ssa_op->op1_def); COPY_SSA_OBJ_TYPE(ssa_op->op1_use, ssa_op->op1_def); } @@ -2991,6 +2995,10 @@ static zend_always_inline zend_result _zend_update_type_info( case ZEND_SEND_FUNC_ARG: if (ssa_op->op1_def >= 0) { tmp = (t1 & MAY_BE_UNDEF)|MAY_BE_REF|MAY_BE_RC1|MAY_BE_RCN|MAY_BE_ANY|MAY_BE_ARRAY_KEY_ANY|MAY_BE_ARRAY_OF_ANY|MAY_BE_ARRAY_OF_REF; + if (opline->opcode == ZEND_SEND_VAR_EX && (t1 & (MAY_BE_ARRAY|MAY_BE_STRING)) && (t1 & MAY_BE_RC1) && !(t1 & (MAY_BE_UNDEF|MAY_BE_REF)) && ssa_vars[ssa_op->op1_def].no_val && !ssa_vars[ssa_op->op1_def].alias) { + /* implicit move may make value undef */ + tmp |= MAY_BE_UNDEF; + } UPDATE_SSA_TYPE(tmp, ssa_op->op1_def); } break; diff --git a/Zend/Optimizer/zend_ssa.c b/Zend/Optimizer/zend_ssa.c index 67165a9b26d7a..e3a1b4d21f8db 100644 --- a/Zend/Optimizer/zend_ssa.c +++ b/Zend/Optimizer/zend_ssa.c @@ -703,6 +703,10 @@ static zend_always_inline int _zend_ssa_rename_op(const zend_op_array *op_array, } break; case ZEND_SEND_VAR: + if (opline->op1_type == IS_CV && ((build_flags & ZEND_SSA_RC_INFERENCE) || opline->op2_type == IS_UNUSED)) { + goto add_op1_def; + } + break; case ZEND_CAST: case ZEND_QM_ASSIGN: case ZEND_JMP_SET: @@ -1680,3 +1684,13 @@ void zend_ssa_rename_var_uses(zend_ssa *ssa, int old, int new, bool update_types old_var->phi_use_chain = NULL; } /* }}} */ + +void zend_ssa_replace_op1_def_op1_use(zend_ssa *ssa, zend_ssa_op *ssa_op) +{ + int op1_new = ssa_op->op1_use; + ZEND_ASSERT(op1_new >= 0); + ZEND_ASSERT(ssa_op->op1_def >= 0); + /* zend_ssa_rename_var_uses() clear use_chain & phi_use_chain for us */ + zend_ssa_rename_var_uses(ssa, ssa_op->op1_def, op1_new, true); + zend_ssa_remove_op1_def(ssa, ssa_op); +} diff --git a/Zend/Optimizer/zend_ssa.h b/Zend/Optimizer/zend_ssa.h index 5a6fce38d2f81..4541d465b2951 100644 --- a/Zend/Optimizer/zend_ssa.h +++ b/Zend/Optimizer/zend_ssa.h @@ -159,6 +159,7 @@ void zend_ssa_remove_uses_of_var(zend_ssa *ssa, int var_num); void zend_ssa_remove_block(zend_op_array *op_array, zend_ssa *ssa, int b); void zend_ssa_rename_var_uses(zend_ssa *ssa, int old_var, int new_var, bool update_types); void zend_ssa_remove_block_from_cfg(zend_ssa *ssa, int b); +void zend_ssa_replace_op1_def_op1_use(zend_ssa *ssa, zend_ssa_op *ssa_op); static zend_always_inline void _zend_ssa_remove_def(zend_ssa_var *var) { diff --git a/Zend/zend_vm_def.h b/Zend/zend_vm_def.h index 0b6604217fa35..5a16f7a930f40 100644 --- a/Zend/zend_vm_def.h +++ b/Zend/zend_vm_def.h @@ -9900,7 +9900,7 @@ ZEND_VM_C_LABEL(fetch_dim_r_index_undef): ZEND_VM_NEXT_OPCODE_CHECK_EXCEPTION(); } -ZEND_VM_HOT_TYPE_SPEC_HANDLER(ZEND_SEND_VAR, op->op2_type == IS_UNUSED && (op1_info & (MAY_BE_UNDEF|MAY_BE_REF)) == 0, ZEND_SEND_VAR_SIMPLE, CV|VAR, NUM) +ZEND_VM_HOT_TYPE_SPEC_HANDLER(ZEND_SEND_VAR, op->op2_type == IS_UNUSED && !op->extended_value && (op1_info & (MAY_BE_UNDEF|MAY_BE_REF)) == 0, ZEND_SEND_VAR_SIMPLE, CV|VAR, NUM) { USE_OPLINE zval *varptr, *arg; @@ -9917,7 +9917,21 @@ ZEND_VM_HOT_TYPE_SPEC_HANDLER(ZEND_SEND_VAR, op->op2_type == IS_UNUSED && (op1_i ZEND_VM_NEXT_OPCODE(); } -ZEND_VM_HOT_TYPE_SPEC_HANDLER(ZEND_SEND_VAR_EX, op->op2_type == IS_UNUSED && op->op2.num <= MAX_ARG_FLAG_NUM && (op1_info & (MAY_BE_UNDEF|MAY_BE_REF)) == 0, ZEND_SEND_VAR_EX_SIMPLE, CV|VAR, UNUSED|NUM) +ZEND_VM_HOT_TYPE_SPEC_HANDLER(ZEND_SEND_VAR, op->extended_value /* extended_value implies here OP2 UNUSED and OP1 not UNDEF or REF */, ZEND_SEND_VAR_SIMPLE_EXT, CV, NUM) +{ + USE_OPLINE + zval *varptr, *arg; + + varptr = GET_OP1_ZVAL_PTR_UNDEF(BP_VAR_R); + arg = ZEND_CALL_VAR(EX(call), opline->result.var); + + ZVAL_COPY_VALUE(arg, varptr); + ZVAL_UNDEF(varptr); + + ZEND_VM_NEXT_OPCODE(); +} + +ZEND_VM_HOT_TYPE_SPEC_HANDLER(ZEND_SEND_VAR_EX, !op->extended_value && op->op2_type == IS_UNUSED && op->op2.num <= MAX_ARG_FLAG_NUM && (op1_info & (MAY_BE_UNDEF|MAY_BE_REF)) == 0, ZEND_SEND_VAR_EX_SIMPLE, CV|VAR, UNUSED|NUM) { USE_OPLINE zval *varptr, *arg; @@ -9939,6 +9953,25 @@ ZEND_VM_HOT_TYPE_SPEC_HANDLER(ZEND_SEND_VAR_EX, op->op2_type == IS_UNUSED && op- ZEND_VM_NEXT_OPCODE(); } +ZEND_VM_HOT_TYPE_SPEC_HANDLER(ZEND_SEND_VAR_EX, op->extended_value && op->op2.num <= MAX_ARG_FLAG_NUM /* extended_value implies here OP2 UNUSED and OP1 not UNDEF or REF */, ZEND_SEND_VAR_EX_SIMPLE_EXT, CV, UNUSED|NUM) +{ + USE_OPLINE + zval *varptr, *arg; + uint32_t arg_num = opline->op2.num; + + if (QUICK_ARG_SHOULD_BE_SENT_BY_REF(EX(call)->func, arg_num)) { + ZEND_VM_DISPATCH_TO_HANDLER(ZEND_SEND_REF); + } + + varptr = GET_OP1_ZVAL_PTR_UNDEF(BP_VAR_R); + arg = ZEND_CALL_VAR(EX(call), opline->result.var); + + ZVAL_COPY_VALUE(arg, varptr); + ZVAL_UNDEF(varptr); + + ZEND_VM_NEXT_OPCODE(); +} + ZEND_VM_HOT_TYPE_SPEC_HANDLER(ZEND_SEND_VAL, op->op1_type == IS_CONST && op->op2_type == IS_UNUSED && !Z_REFCOUNTED_P(RT_CONSTANT(op, op->op1)), ZEND_SEND_VAL_SIMPLE, CONST, NUM) { USE_OPLINE diff --git a/Zend/zend_vm_execute.h b/Zend/zend_vm_execute.h index 21b927c02b895..4286880cd2f91 100644 --- a/Zend/zend_vm_execute.h +++ b/Zend/zend_vm_execute.h @@ -40531,6 +40531,20 @@ static ZEND_VM_HOT ZEND_OPCODE_HANDLER_RET ZEND_FASTCALL ZEND_SEND_VAR_SIMPLE_SP ZEND_VM_NEXT_OPCODE(); } +static ZEND_VM_HOT ZEND_OPCODE_HANDLER_RET ZEND_FASTCALL ZEND_SEND_VAR_SIMPLE_EXT_SPEC_CV_HANDLER(ZEND_OPCODE_HANDLER_ARGS) +{ + USE_OPLINE + zval *varptr, *arg; + + varptr = EX_VAR(opline->op1.var); + arg = ZEND_CALL_VAR(EX(call), opline->result.var); + + ZVAL_COPY_VALUE(arg, varptr); + ZVAL_UNDEF(varptr); + + ZEND_VM_NEXT_OPCODE(); +} + static ZEND_OPCODE_HANDLER_RET ZEND_FASTCALL ZEND_DIV_SPEC_CV_CONST_HANDLER(ZEND_OPCODE_HANDLER_ARGS) { USE_OPLINE @@ -49788,6 +49802,25 @@ static ZEND_VM_HOT ZEND_OPCODE_HANDLER_RET ZEND_FASTCALL ZEND_SEND_VAR_EX_SIMPLE ZEND_VM_NEXT_OPCODE(); } +static ZEND_VM_HOT ZEND_OPCODE_HANDLER_RET ZEND_FASTCALL ZEND_SEND_VAR_EX_SIMPLE_EXT_SPEC_CV_UNUSED_HANDLER(ZEND_OPCODE_HANDLER_ARGS) +{ + USE_OPLINE + zval *varptr, *arg; + uint32_t arg_num = opline->op2.num; + + if (QUICK_ARG_SHOULD_BE_SENT_BY_REF(EX(call)->func, arg_num)) { + ZEND_VM_TAIL_CALL(ZEND_SEND_REF_SPEC_CV_UNUSED_HANDLER(ZEND_OPCODE_HANDLER_ARGS_PASSTHRU)); + } + + varptr = EX_VAR(opline->op1.var); + arg = ZEND_CALL_VAR(EX(call), opline->result.var); + + ZVAL_COPY_VALUE(arg, varptr); + ZVAL_UNDEF(varptr); + + ZEND_VM_NEXT_OPCODE(); +} + static ZEND_OPCODE_HANDLER_RET ZEND_FASTCALL ZEND_DIV_SPEC_CV_CV_HANDLER(ZEND_OPCODE_HANDLER_ARGS) { USE_OPLINE @@ -56760,11 +56793,13 @@ ZEND_API void execute_ex(zend_execute_data *ex) (void*)&&ZEND_SEND_VAR_SIMPLE_SPEC_VAR_LABEL, (void*)&&ZEND_NULL_LABEL, (void*)&&ZEND_SEND_VAR_SIMPLE_SPEC_CV_LABEL, + (void*)&&ZEND_SEND_VAR_SIMPLE_EXT_SPEC_CV_LABEL, (void*)&&ZEND_NULL_LABEL, (void*)&&ZEND_NULL_LABEL, (void*)&&ZEND_SEND_VAR_EX_SIMPLE_SPEC_VAR_UNUSED_LABEL, (void*)&&ZEND_NULL_LABEL, (void*)&&ZEND_SEND_VAR_EX_SIMPLE_SPEC_CV_UNUSED_LABEL, + (void*)&&ZEND_SEND_VAR_EX_SIMPLE_EXT_SPEC_CV_UNUSED_LABEL, (void*)&&ZEND_SEND_VAL_SIMPLE_SPEC_CONST_LABEL, (void*)&&ZEND_SEND_VAL_EX_SIMPLE_SPEC_CONST_LABEL, (void*)&&ZEND_FE_FETCH_R_SIMPLE_SPEC_VAR_CV_RETVAL_UNUSED_LABEL, @@ -60487,6 +60522,10 @@ ZEND_API void execute_ex(zend_execute_data *ex) VM_TRACE(ZEND_SEND_VAR_SIMPLE_SPEC_CV) ZEND_SEND_VAR_SIMPLE_SPEC_CV_HANDLER(ZEND_OPCODE_HANDLER_ARGS_PASSTHRU); HYBRID_BREAK(); + HYBRID_CASE(ZEND_SEND_VAR_SIMPLE_EXT_SPEC_CV): + VM_TRACE(ZEND_SEND_VAR_SIMPLE_EXT_SPEC_CV) + ZEND_SEND_VAR_SIMPLE_EXT_SPEC_CV_HANDLER(ZEND_OPCODE_HANDLER_ARGS_PASSTHRU); + HYBRID_BREAK(); HYBRID_CASE(ZEND_DIV_SPEC_CV_CONST): VM_TRACE(ZEND_DIV_SPEC_CV_CONST) ZEND_DIV_SPEC_CV_CONST_HANDLER(ZEND_OPCODE_HANDLER_ARGS_PASSTHRU); @@ -61107,6 +61146,10 @@ ZEND_API void execute_ex(zend_execute_data *ex) VM_TRACE(ZEND_SEND_VAR_EX_SIMPLE_SPEC_CV_UNUSED) ZEND_SEND_VAR_EX_SIMPLE_SPEC_CV_UNUSED_HANDLER(ZEND_OPCODE_HANDLER_ARGS_PASSTHRU); HYBRID_BREAK(); + HYBRID_CASE(ZEND_SEND_VAR_EX_SIMPLE_EXT_SPEC_CV_UNUSED): + VM_TRACE(ZEND_SEND_VAR_EX_SIMPLE_EXT_SPEC_CV_UNUSED) + ZEND_SEND_VAR_EX_SIMPLE_EXT_SPEC_CV_UNUSED_HANDLER(ZEND_OPCODE_HANDLER_ARGS_PASSTHRU); + HYBRID_BREAK(); HYBRID_CASE(ZEND_DIV_SPEC_CV_CV): VM_TRACE(ZEND_DIV_SPEC_CV_CV) ZEND_DIV_SPEC_CV_CV_HANDLER(ZEND_OPCODE_HANDLER_ARGS_PASSTHRU); @@ -64864,11 +64907,13 @@ void zend_vm_init(void) ZEND_SEND_VAR_SIMPLE_SPEC_VAR_HANDLER, ZEND_NULL_HANDLER, ZEND_SEND_VAR_SIMPLE_SPEC_CV_HANDLER, + ZEND_SEND_VAR_SIMPLE_EXT_SPEC_CV_HANDLER, ZEND_NULL_HANDLER, ZEND_NULL_HANDLER, ZEND_SEND_VAR_EX_SIMPLE_SPEC_VAR_UNUSED_HANDLER, ZEND_NULL_HANDLER, ZEND_SEND_VAR_EX_SIMPLE_SPEC_CV_UNUSED_HANDLER, + ZEND_SEND_VAR_EX_SIMPLE_EXT_SPEC_CV_UNUSED_HANDLER, ZEND_SEND_VAL_SIMPLE_SPEC_CONST_HANDLER, ZEND_SEND_VAL_EX_SIMPLE_SPEC_CONST_HANDLER, ZEND_FE_FETCH_R_SIMPLE_SPEC_VAR_CV_RETVAL_UNUSED_HANDLER, @@ -64921,7 +64966,7 @@ void zend_vm_init(void) 1255, 1256 | SPEC_RULE_OP1, 1261 | SPEC_RULE_OP1, - 3470, + 3472, 1266 | SPEC_RULE_OP1, 1271 | SPEC_RULE_OP1, 1276 | SPEC_RULE_OP2, @@ -65079,59 +65124,59 @@ void zend_vm_init(void) 2564, 2565, 2566, - 3470, - 3470, - 3470, - 3470, - 3470, - 3470, - 3470, - 3470, - 3470, - 3470, - 3470, - 3470, - 3470, - 3470, - 3470, - 3470, - 3470, - 3470, - 3470, - 3470, - 3470, - 3470, - 3470, - 3470, - 3470, - 3470, - 3470, - 3470, - 3470, - 3470, - 3470, - 3470, - 3470, - 3470, - 3470, - 3470, - 3470, - 3470, - 3470, - 3470, - 3470, - 3470, - 3470, - 3470, - 3470, - 3470, - 3470, - 3470, - 3470, - 3470, - 3470, - 3470, - 3470, + 3472, + 3472, + 3472, + 3472, + 3472, + 3472, + 3472, + 3472, + 3472, + 3472, + 3472, + 3472, + 3472, + 3472, + 3472, + 3472, + 3472, + 3472, + 3472, + 3472, + 3472, + 3472, + 3472, + 3472, + 3472, + 3472, + 3472, + 3472, + 3472, + 3472, + 3472, + 3472, + 3472, + 3472, + 3472, + 3472, + 3472, + 3472, + 3472, + 3472, + 3472, + 3472, + 3472, + 3472, + 3472, + 3472, + 3472, + 3472, + 3472, + 3472, + 3472, + 3472, + 3472, }; #if (ZEND_VM_KIND == ZEND_VM_KIND_HYBRID) zend_opcode_handler_funcs = labels; @@ -65508,17 +65553,19 @@ ZEND_API void ZEND_FASTCALL zend_vm_set_opcode_handler_ex(zend_op* op, uint32_t break; case ZEND_SEND_VAL: if (op->op1_type == IS_CONST && op->op2_type == IS_UNUSED && !Z_REFCOUNTED_P(RT_CONSTANT(op, op->op1))) { - spec = 3466; + spec = 3468; } break; case ZEND_SEND_VAR_EX: - if (op->op2_type == IS_UNUSED && op->op2.num <= MAX_ARG_FLAG_NUM && (op1_info & (MAY_BE_UNDEF|MAY_BE_REF)) == 0) { - spec = 3461 | SPEC_RULE_OP1; + if (!op->extended_value && op->op2_type == IS_UNUSED && op->op2.num <= MAX_ARG_FLAG_NUM && (op1_info & (MAY_BE_UNDEF|MAY_BE_REF)) == 0) { + spec = 3462 | SPEC_RULE_OP1; + } else if (op->extended_value && op->op2.num <= MAX_ARG_FLAG_NUM /* extended_value implies here OP2 UNUSED and OP1 not UNDEF or REF */) { + spec = 3467; } break; case ZEND_FE_FETCH_R: if (op->op2_type == IS_CV && (op1_info & (MAY_BE_ANY|MAY_BE_REF)) == MAY_BE_ARRAY) { - spec = 3468 | SPEC_RULE_RETVAL; + spec = 3470 | SPEC_RULE_RETVAL; } break; case ZEND_FETCH_DIM_R: @@ -65531,12 +65578,14 @@ ZEND_API void ZEND_FASTCALL zend_vm_set_opcode_handler_ex(zend_op* op, uint32_t break; case ZEND_SEND_VAL_EX: if (op->op2_type == IS_UNUSED && op->op2.num <= MAX_ARG_FLAG_NUM && op->op1_type == IS_CONST && !Z_REFCOUNTED_P(RT_CONSTANT(op, op->op1))) { - spec = 3467; + spec = 3469; } break; case ZEND_SEND_VAR: - if (op->op2_type == IS_UNUSED && (op1_info & (MAY_BE_UNDEF|MAY_BE_REF)) == 0) { + if (op->op2_type == IS_UNUSED && !op->extended_value && (op1_info & (MAY_BE_UNDEF|MAY_BE_REF)) == 0) { spec = 3456 | SPEC_RULE_OP1; + } else if (op->extended_value /* extended_value implies here OP2 UNUSED and OP1 not UNDEF or REF */) { + spec = 3461; } break; case ZEND_BW_OR: diff --git a/Zend/zend_vm_handlers.h b/Zend/zend_vm_handlers.h index fae2138ef912e..38c1dc3eae3b3 100644 --- a/Zend/zend_vm_handlers.h +++ b/Zend/zend_vm_handlers.h @@ -1850,10 +1850,12 @@ _(3455, ZEND_FETCH_DIM_R_INDEX_SPEC_CV_TMPVARCV) \ _(3458, ZEND_SEND_VAR_SIMPLE_SPEC_VAR) \ _(3460, ZEND_SEND_VAR_SIMPLE_SPEC_CV) \ - _(3463, ZEND_SEND_VAR_EX_SIMPLE_SPEC_VAR_UNUSED) \ - _(3465, ZEND_SEND_VAR_EX_SIMPLE_SPEC_CV_UNUSED) \ - _(3466, ZEND_SEND_VAL_SIMPLE_SPEC_CONST) \ - _(3467, ZEND_SEND_VAL_EX_SIMPLE_SPEC_CONST) \ - _(3468, ZEND_FE_FETCH_R_SIMPLE_SPEC_VAR_CV_RETVAL_UNUSED) \ - _(3469, ZEND_FE_FETCH_R_SIMPLE_SPEC_VAR_CV_RETVAL_USED) \ - _(3469+1, ZEND_NULL) + _(3461, ZEND_SEND_VAR_SIMPLE_EXT_SPEC_CV) \ + _(3464, ZEND_SEND_VAR_EX_SIMPLE_SPEC_VAR_UNUSED) \ + _(3466, ZEND_SEND_VAR_EX_SIMPLE_SPEC_CV_UNUSED) \ + _(3467, ZEND_SEND_VAR_EX_SIMPLE_EXT_SPEC_CV_UNUSED) \ + _(3468, ZEND_SEND_VAL_SIMPLE_SPEC_CONST) \ + _(3469, ZEND_SEND_VAL_EX_SIMPLE_SPEC_CONST) \ + _(3470, ZEND_FE_FETCH_R_SIMPLE_SPEC_VAR_CV_RETVAL_UNUSED) \ + _(3471, ZEND_FE_FETCH_R_SIMPLE_SPEC_VAR_CV_RETVAL_USED) \ + _(3471+1, ZEND_NULL) From 4749e5b1606c0b7b236f13f1e15bc0562507e659 Mon Sep 17 00:00:00 2001 From: nielsdos <7771979+nielsdos@users.noreply.github.com> Date: Fri, 28 Apr 2023 17:16:13 +0200 Subject: [PATCH 2/4] Add array_micro_bench.php --- Zend/array_micro_bench.php | 66 ++++++++++++++++++++++++++++++++++++++ Zend/bench.php | 36 +-------------------- Zend/bench_common.php | 48 +++++++++++++++++++++++++++ Zend/micro_bench.php | 47 +-------------------------- 4 files changed, 116 insertions(+), 81 deletions(-) create mode 100644 Zend/array_micro_bench.php create mode 100644 Zend/bench_common.php diff --git a/Zend/array_micro_bench.php b/Zend/array_micro_bench.php new file mode 100644 index 0000000000000..ca9ec218bbefc --- /dev/null +++ b/Zend/array_micro_bench.php @@ -0,0 +1,66 @@ + Date: Sat, 29 Apr 2023 00:06:43 +0200 Subject: [PATCH 3/4] RC1 optimisation for ucfirst and lcfirst --- Zend/zend_types.h | 5 +++++ ext/standard/string.c | 18 ++++++++++++++++-- 2 files changed, 21 insertions(+), 2 deletions(-) diff --git a/Zend/zend_types.h b/Zend/zend_types.h index c341ffa0b4d8c..fc7ae3f361d6e 100644 --- a/Zend/zend_types.h +++ b/Zend/zend_types.h @@ -1512,4 +1512,9 @@ static zend_always_inline bool zend_may_modify_arg_in_place(const zval *arg) return Z_REFCOUNTED_P(arg) && !(GC_FLAGS(Z_COUNTED_P(arg)) & (GC_IMMUTABLE | GC_PERSISTENT)) && Z_REFCOUNT_P(arg) == 1; } +static zend_always_inline bool zend_may_modify_string_in_place(const zend_string *arg) +{ + return !(GC_FLAGS(arg) & (GC_IMMUTABLE | GC_PERSISTENT)) && GC_REFCOUNT(arg) == 1; +} + #endif /* ZEND_TYPES_H */ diff --git a/ext/standard/string.c b/ext/standard/string.c index 335e6fd897128..17840d4803420 100644 --- a/ext/standard/string.c +++ b/ext/standard/string.c @@ -2341,7 +2341,14 @@ static zend_string* php_ucfirst(zend_string *str) if (r == ch) { return zend_string_copy(str); } else { - zend_string *s = zend_string_init(ZSTR_VAL(str), ZSTR_LEN(str), 0); + zend_string *s; + if (zend_may_modify_string_in_place(str)) { + s = str; + zend_string_forget_hash_val(s); + GC_ADDREF(s); + } else { + s = zend_string_init(ZSTR_VAL(str), ZSTR_LEN(str), false); + } ZSTR_VAL(s)[0] = r; return s; } @@ -2373,7 +2380,14 @@ static zend_string* php_lcfirst(zend_string *str) if (r == ZSTR_VAL(str)[0]) { return zend_string_copy(str); } else { - zend_string *s = zend_string_init(ZSTR_VAL(str), ZSTR_LEN(str), 0); + zend_string *s; + if (zend_may_modify_string_in_place(str)) { + s = str; + zend_string_forget_hash_val(s); + GC_ADDREF(s); + } else { + s = zend_string_init(ZSTR_VAL(str), ZSTR_LEN(str), false); + } ZSTR_VAL(s)[0] = r; return s; } From 945c0ba3076dbfaa997338d75e056d263d970e3e Mon Sep 17 00:00:00 2001 From: Niels Dossche <7771979+nielsdos@users.noreply.github.com> Date: Sat, 29 Apr 2023 00:20:37 +0200 Subject: [PATCH 4/4] RC1 optimisation for strto{lower,upper} We can't unconditionally allow inplace modification in zend_string_toupper_ex and zend_string_tolower_ex because their API contract expects a copy. --- Zend/zend_operators.c | 40 ++++++++++++++++++++++++++++++---------- Zend/zend_operators.h | 6 ++++-- ext/standard/string.c | 4 ++-- 3 files changed, 36 insertions(+), 14 deletions(-) diff --git a/Zend/zend_operators.c b/Zend/zend_operators.c index 00286cac388c7..6c423297ecbb6 100644 --- a/Zend/zend_operators.c +++ b/Zend/zend_operators.c @@ -2877,7 +2877,21 @@ ZEND_API char* ZEND_FASTCALL zend_str_toupper_dup_ex(const char *source, size_t } /* }}} */ -ZEND_API zend_string* ZEND_FASTCALL zend_string_tolower_ex(zend_string *str, bool persistent) /* {{{ */ +static zend_string* ZEND_FASTCALL zend_string_alloc_or_partial_dup(zend_string *str, bool persistent, bool inplace, const unsigned char *p) +{ + if (inplace) { + ZEND_ASSERT(!persistent); + zend_string_forget_hash_val(str); + GC_ADDREF(str); + return str; + } else { + zend_string *res = zend_string_alloc(ZSTR_LEN(str), persistent); + memcpy(ZSTR_VAL(res), ZSTR_VAL(str), p - (unsigned char *) ZSTR_VAL(str)); + return res; + } +} + +ZEND_API zend_string* ZEND_FASTCALL zend_string_tolower_ex_maybe_inplace(zend_string *str, bool persistent, bool inplace) /* {{{ */ { size_t length = ZSTR_LEN(str); unsigned char *p = (unsigned char *) ZSTR_VAL(str); @@ -2888,8 +2902,7 @@ ZEND_API zend_string* ZEND_FASTCALL zend_string_tolower_ex(zend_string *str, boo while (p + BLOCKCONV_STRIDE <= end) { BLOCKCONV_LOAD(p); if (BLOCKCONV_FOUND()) { - zend_string *res = zend_string_alloc(length, persistent); - memcpy(ZSTR_VAL(res), ZSTR_VAL(str), p - (unsigned char *) ZSTR_VAL(str)); + zend_string *res = zend_string_alloc_or_partial_dup(str, persistent, inplace, p); unsigned char *q = (unsigned char*) ZSTR_VAL(res) + (p - (unsigned char*) ZSTR_VAL(str)); /* Lowercase the chunk we already compared. */ @@ -2909,8 +2922,7 @@ ZEND_API zend_string* ZEND_FASTCALL zend_string_tolower_ex(zend_string *str, boo while (p < end) { if (*p != zend_tolower_ascii(*p)) { - zend_string *res = zend_string_alloc(length, persistent); - memcpy(ZSTR_VAL(res), ZSTR_VAL(str), p - (unsigned char*) ZSTR_VAL(str)); + zend_string *res = zend_string_alloc_or_partial_dup(str, persistent, inplace, p); unsigned char *q = (unsigned char*) ZSTR_VAL(res) + (p - (unsigned char*) ZSTR_VAL(str)); while (p < end) { @@ -2926,7 +2938,12 @@ ZEND_API zend_string* ZEND_FASTCALL zend_string_tolower_ex(zend_string *str, boo } /* }}} */ -ZEND_API zend_string* ZEND_FASTCALL zend_string_toupper_ex(zend_string *str, bool persistent) /* {{{ */ +ZEND_API zend_string* ZEND_FASTCALL zend_string_tolower_ex(zend_string *str, bool persistent) +{ + return zend_string_tolower_ex_maybe_inplace(str, persistent, false); +} + +ZEND_API zend_string* ZEND_FASTCALL zend_string_toupper_ex_maybe_inplace(zend_string *str, bool persistent, bool inplace) /* {{{ */ { size_t length = ZSTR_LEN(str); unsigned char *p = (unsigned char *) ZSTR_VAL(str); @@ -2937,8 +2954,7 @@ ZEND_API zend_string* ZEND_FASTCALL zend_string_toupper_ex(zend_string *str, boo while (p + BLOCKCONV_STRIDE <= end) { BLOCKCONV_LOAD(p); if (BLOCKCONV_FOUND()) { - zend_string *res = zend_string_alloc(length, persistent); - memcpy(ZSTR_VAL(res), ZSTR_VAL(str), p - (unsigned char *) ZSTR_VAL(str)); + zend_string *res = zend_string_alloc_or_partial_dup(str, persistent, inplace, p); unsigned char *q = (unsigned char *) ZSTR_VAL(res) + (p - (unsigned char *) ZSTR_VAL(str)); /* Uppercase the chunk we already compared. */ @@ -2958,8 +2974,7 @@ ZEND_API zend_string* ZEND_FASTCALL zend_string_toupper_ex(zend_string *str, boo while (p < end) { if (*p != zend_toupper_ascii(*p)) { - zend_string *res = zend_string_alloc(length, persistent); - memcpy(ZSTR_VAL(res), ZSTR_VAL(str), p - (unsigned char*) ZSTR_VAL(str)); + zend_string *res = zend_string_alloc_or_partial_dup(str, persistent, inplace, p); unsigned char *q = (unsigned char *) ZSTR_VAL(res) + (p - (unsigned char *) ZSTR_VAL(str)); while (p < end) { @@ -2975,6 +2990,11 @@ ZEND_API zend_string* ZEND_FASTCALL zend_string_toupper_ex(zend_string *str, boo } /* }}} */ +ZEND_API zend_string* ZEND_FASTCALL zend_string_toupper_ex(zend_string *str, bool persistent) +{ + return zend_string_toupper_ex_maybe_inplace(str, persistent, false); +} + ZEND_API int ZEND_FASTCALL zend_binary_strcmp(const char *s1, size_t len1, const char *s2, size_t len2) /* {{{ */ { int retval; diff --git a/Zend/zend_operators.h b/Zend/zend_operators.h index 40974da03249f..380be2cc3dc4f 100644 --- a/Zend/zend_operators.h +++ b/Zend/zend_operators.h @@ -438,13 +438,15 @@ ZEND_API char* ZEND_FASTCALL zend_str_toupper_dup(const char *source, siz ZEND_API char* ZEND_FASTCALL zend_str_tolower_dup_ex(const char *source, size_t length); ZEND_API char* ZEND_FASTCALL zend_str_toupper_dup_ex(const char *source, size_t length); ZEND_API zend_string* ZEND_FASTCALL zend_string_tolower_ex(zend_string *str, bool persistent); +ZEND_API zend_string* ZEND_FASTCALL zend_string_tolower_ex_maybe_inplace(zend_string *str, bool persistent, bool inplace); ZEND_API zend_string* ZEND_FASTCALL zend_string_toupper_ex(zend_string *str, bool persistent); +ZEND_API zend_string* ZEND_FASTCALL zend_string_toupper_ex_maybe_inplace(zend_string *str, bool persistent, bool inplace); static zend_always_inline zend_string* zend_string_tolower(zend_string *str) { - return zend_string_tolower_ex(str, false); + return zend_string_tolower_ex_maybe_inplace(str, false, false); } static zend_always_inline zend_string* zend_string_toupper(zend_string *str) { - return zend_string_toupper_ex(str, false); + return zend_string_toupper_ex_maybe_inplace(str, false, false); } ZEND_API int ZEND_FASTCALL zend_binary_zval_strcmp(zval *s1, zval *s2); diff --git a/ext/standard/string.c b/ext/standard/string.c index 17840d4803420..7bb544c0afa7c 100644 --- a/ext/standard/string.c +++ b/ext/standard/string.c @@ -1160,7 +1160,7 @@ PHP_FUNCTION(strtoupper) Z_PARAM_STR(arg) ZEND_PARSE_PARAMETERS_END(); - RETURN_STR(zend_string_toupper(arg)); + RETURN_STR(zend_string_toupper_ex_maybe_inplace(arg, false, zend_may_modify_string_in_place(arg))); } /* }}} */ @@ -1188,7 +1188,7 @@ PHP_FUNCTION(strtolower) Z_PARAM_STR(str) ZEND_PARSE_PARAMETERS_END(); - RETURN_STR(zend_string_tolower(str)); + RETURN_STR(zend_string_tolower_ex_maybe_inplace(str, false, zend_may_modify_string_in_place(str))); } /* }}} */Note: This service is not intended for secure transactions such as banking, social media, email, or purchasing. Use at your own risk. We assume no liability whatsoever for broken pages.
Alternative Proxies: