From 18b53938bb49cd9f984d5930e404f7596193f21a Mon Sep 17 00:00:00 2001 From: Ilija Tovilo Date: Sun, 4 May 2025 18:16:13 +0200 Subject: [PATCH 1/6] Add FETCH_DIM_R cache slot --- Zend/Optimizer/compact_literals.c | 6 + Zend/zend_compile.c | 7 +- Zend/zend_execute.c | 23 ++- Zend/zend_vm_def.h | 50 +++++++ Zend/zend_vm_execute.h | 230 +++++++++++++++++++++++------- Zend/zend_vm_handlers.h | 43 +++--- 6 files changed, 277 insertions(+), 82 deletions(-) diff --git a/Zend/Optimizer/compact_literals.c b/Zend/Optimizer/compact_literals.c index d0aaccec7ce2c..be5092fbcfd4e 100644 --- a/Zend/Optimizer/compact_literals.c +++ b/Zend/Optimizer/compact_literals.c @@ -740,6 +740,12 @@ void zend_optimizer_compact_literals(zend_op_array *op_array, zend_optimizer_ctx cache_size += 2 * sizeof(void *); } break; + case ZEND_FETCH_DIM_R: + if (opline->op1_type != IS_CONST && opline->op2_type == IS_CONST) { + opline->extended_value = cache_size; + cache_size += sizeof(void *); + } + break; } opline++; } diff --git a/Zend/zend_compile.c b/Zend/zend_compile.c index 0669d106f15e9..c4fad5b8acc67 100644 --- a/Zend/zend_compile.c +++ b/Zend/zend_compile.c @@ -3082,6 +3082,9 @@ static zend_op *zend_delayed_compile_dim(znode *result, zend_ast *ast, uint32_t opline = zend_delayed_emit_op(result, ZEND_FETCH_DIM_R, &var_node, &dim_node); zend_adjust_for_fetch_type(opline, result, type); + if (type == BP_VAR_R && opline->op1_type != IS_CONST && opline->op2_type == IS_CONST) { + opline->extended_value = zend_alloc_cache_slot(); + } if (by_ref) { opline->extended_value = ZEND_FETCH_DIM_REF; } @@ -8361,10 +8364,10 @@ static zend_op_array *zend_compile_func_decl_ex( "nodiscard", sizeof("nodiscard")-1 ); - + if (nodiscard_attribute) { op_array->fn_flags |= ZEND_ACC_NODISCARD; - } + } } /* Do not leak the class scope into free standing functions, even if they are dynamically diff --git a/Zend/zend_execute.c b/Zend/zend_execute.c index 0fbfdfa07ef04..71994719f5970 100644 --- a/Zend/zend_execute.c +++ b/Zend/zend_execute.c @@ -2996,7 +2996,7 @@ static zend_never_inline void ZEND_FASTCALL zend_fetch_dimension_address_UNSET(z zend_fetch_dimension_address(result, container_ptr, dim, dim_type, BP_VAR_UNSET EXECUTE_DATA_CC); } -static zend_always_inline void zend_fetch_dimension_address_read(zval *result, zval *container, zval *dim, int dim_type, int type, bool is_list, int slow EXECUTE_DATA_DC) +static zend_always_inline void zend_fetch_dimension_address_read(zval *result, zval *container, zval *dim, int dim_type, int type, bool is_list, int slow, void **cache_slot EXECUTE_DATA_DC) { zval *retval; @@ -3005,6 +3005,10 @@ static zend_always_inline void zend_fetch_dimension_address_read(zval *result, z try_array: retval = zend_fetch_dimension_address_inner(Z_ARRVAL_P(container), dim, dim_type, type EXECUTE_DATA_CC); ZVAL_COPY_DEREF(result, retval); + if (cache_slot && !HT_IS_PACKED(Z_ARRVAL_P(container))) { + Bucket *bucket = (Bucket*)((uintptr_t)retval - XtOffsetOf(Bucket, val)); + CACHE_PTR_EX(cache_slot, (void *)(bucket - Z_ARRVAL_P(container)->arData + 1)); + } return; } else if (EXPECTED(Z_TYPE_P(container) == IS_REFERENCE)) { container = Z_REFVAL_P(container); @@ -3145,30 +3149,37 @@ static zend_always_inline void zend_fetch_dimension_address_read(zval *result, z static zend_never_inline void ZEND_FASTCALL zend_fetch_dimension_address_read_R(zval *container, zval *dim, int dim_type OPLINE_DC EXECUTE_DATA_DC) { zval *result = EX_VAR(opline->result.var); - zend_fetch_dimension_address_read(result, container, dim, dim_type, BP_VAR_R, 0, 0 EXECUTE_DATA_CC); + zend_fetch_dimension_address_read(result, container, dim, dim_type, BP_VAR_R, 0, 0, NULL EXECUTE_DATA_CC); +} + +static zend_never_inline void ZEND_FASTCALL zend_fetch_dimension_address_read_R_ex(zval *container, zval *dim, int dim_type, void **cache_slot OPLINE_DC EXECUTE_DATA_DC) +{ + zval *result = EX_VAR(opline->result.var); + ZEND_ASSERT(cache_slot); + zend_fetch_dimension_address_read(result, container, dim, dim_type, BP_VAR_R, 0, 0, cache_slot EXECUTE_DATA_CC); } static zend_never_inline void zend_fetch_dimension_address_read_R_slow(zval *container, zval *dim OPLINE_DC EXECUTE_DATA_DC) { zval *result = EX_VAR(opline->result.var); - zend_fetch_dimension_address_read(result, container, dim, IS_CV, BP_VAR_R, 0, 1 EXECUTE_DATA_CC); + zend_fetch_dimension_address_read(result, container, dim, IS_CV, BP_VAR_R, 0, 1, NULL EXECUTE_DATA_CC); } static zend_never_inline void ZEND_FASTCALL zend_fetch_dimension_address_read_IS(zval *container, zval *dim, int dim_type OPLINE_DC EXECUTE_DATA_DC) { zval *result = EX_VAR(opline->result.var); - zend_fetch_dimension_address_read(result, container, dim, dim_type, BP_VAR_IS, 0, 0 EXECUTE_DATA_CC); + zend_fetch_dimension_address_read(result, container, dim, dim_type, BP_VAR_IS, 0, 0, NULL EXECUTE_DATA_CC); } static zend_never_inline void ZEND_FASTCALL zend_fetch_dimension_address_LIST_r(zval *container, zval *dim, int dim_type OPLINE_DC EXECUTE_DATA_DC) { zval *result = EX_VAR(opline->result.var); - zend_fetch_dimension_address_read(result, container, dim, dim_type, BP_VAR_R, 1, 0 EXECUTE_DATA_CC); + zend_fetch_dimension_address_read(result, container, dim, dim_type, BP_VAR_R, 1, 0, NULL EXECUTE_DATA_CC); } ZEND_API void zend_fetch_dimension_const(zval *result, zval *container, zval *dim, int type) { - zend_fetch_dimension_address_read(result, container, dim, IS_TMP_VAR, type, 0, 0 NO_EXECUTE_DATA_CC); + zend_fetch_dimension_address_read(result, container, dim, IS_TMP_VAR, type, 0, 0, NULL NO_EXECUTE_DATA_CC); } static zend_never_inline zval* ZEND_FASTCALL zend_find_array_dim_slow(HashTable *ht, zval *offset EXECUTE_DATA_DC) diff --git a/Zend/zend_vm_def.h b/Zend/zend_vm_def.h index 9c2ba0038b4a4..3284138079099 100644 --- a/Zend/zend_vm_def.h +++ b/Zend/zend_vm_def.h @@ -10265,6 +10265,56 @@ ZEND_VM_HOT_TYPE_SPEC_HANDLER(ZEND_QM_ASSIGN, ((op->op1_type == IS_CONST) ? !Z_R ZEND_VM_NEXT_OPCODE(); } +ZEND_VM_HOT_TYPE_SPEC_HANDLER(ZEND_FETCH_DIM_R, (op->op1_type != IS_CONST && op->op2_type == IS_CONST && !(op2_info & (MAY_BE_ANY-MAY_BE_STRING))), ZEND_FETCH_DIM_R_STRING_INDEX, TMPVAR|CV, CONST, CACHE_SLOT) +{ + USE_OPLINE + SAVE_OPLINE(); + + zval *container, *dim; + zend_long offset; + HashTable *ht; + + container = GET_OP1_ZVAL_PTR_UNDEF(BP_VAR_R); + dim = GET_OP2_ZVAL_PTR_UNDEF(BP_VAR_R); + if (EXPECTED(Z_TYPE_P(container) == IS_ARRAY)) { +ZEND_VM_C_LABEL(fetch_dim_r_const_index_array): + ht = Z_ARRVAL_P(container); + uintptr_t offset = (uintptr_t)CACHED_PTR(opline->extended_value); + if (offset && !HT_IS_PACKED(ht) && ht->nNumUsed >= offset) { + Bucket *b = &ht->arData[offset - 1]; + if (b->key && zend_string_equals(b->key, Z_STR_P(dim))) { + ZVAL_COPY_DEREF(EX_VAR(opline->result.var), &b->val); + FREE_OP1(); + ZEND_VM_NEXT_OPCODE_CHECK_EXCEPTION(); + } + } + + zend_fetch_dimension_address_read_R_ex(container, dim, OP2_TYPE, CACHE_ADDR(opline->extended_value) OPLINE_CC EXECUTE_DATA_CC); + FREE_OP1(); + ZEND_VM_NEXT_OPCODE_CHECK_EXCEPTION(); + } else if (EXPECTED(Z_TYPE_P(container) == IS_REFERENCE)) { + container = Z_REFVAL_P(container); + if (EXPECTED(Z_TYPE_P(container) == IS_ARRAY)) { + ZEND_VM_C_GOTO(fetch_dim_r_const_index_array); + } else { + ZEND_VM_C_GOTO(fetch_dim_r_const_index_slow); + } + } else { +ZEND_VM_C_LABEL(fetch_dim_r_const_index_slow): + if (OP2_TYPE == IS_CONST && Z_EXTRA_P(dim) == ZEND_EXTRA_VALUE) { + dim++; + } + zend_fetch_dimension_address_read_R_slow(container, dim OPLINE_CC EXECUTE_DATA_CC); + FREE_OP1(); + ZEND_VM_NEXT_OPCODE_CHECK_EXCEPTION(); + } + + ZVAL_NULL(EX_VAR(opline->result.var)); + zend_undefined_offset(offset); + FREE_OP1(); + ZEND_VM_NEXT_OPCODE_CHECK_EXCEPTION(); +} + ZEND_VM_HOT_TYPE_SPEC_HANDLER(ZEND_FETCH_DIM_R, (!(op2_info & (MAY_BE_UNDEF|MAY_BE_NULL|MAY_BE_STRING|MAY_BE_ARRAY|MAY_BE_OBJECT|MAY_BE_RESOURCE|MAY_BE_REF))), ZEND_FETCH_DIM_R_INDEX, CONST|TMPVAR|CV, CONST|TMPVARCV, SPEC(NO_CONST_CONST)) { USE_OPLINE diff --git a/Zend/zend_vm_execute.h b/Zend/zend_vm_execute.h index 226e0446abbd1..2fba725ef3358 100644 --- a/Zend/zend_vm_execute.h +++ b/Zend/zend_vm_execute.h @@ -17116,6 +17116,56 @@ static ZEND_OPCODE_HANDLER_RET ZEND_FASTCALL ZEND_INSTANCEOF_SPEC_TMPVAR_CONST_H ZEND_VM_SMART_BRANCH(result, 1); } +static ZEND_VM_HOT ZEND_OPCODE_HANDLER_RET ZEND_FASTCALL ZEND_FETCH_DIM_R_STRING_INDEX_SPEC_TMPVAR_CONST_HANDLER(ZEND_OPCODE_HANDLER_ARGS) +{ + USE_OPLINE + SAVE_OPLINE(); + + zval *container, *dim; + zend_long offset; + HashTable *ht; + + container = _get_zval_ptr_var(opline->op1.var EXECUTE_DATA_CC); + dim = RT_CONSTANT(opline, opline->op2); + if (EXPECTED(Z_TYPE_P(container) == IS_ARRAY)) { +fetch_dim_r_const_index_array: + ht = Z_ARRVAL_P(container); + uintptr_t offset = (uintptr_t)CACHED_PTR(opline->extended_value); + if (offset && !HT_IS_PACKED(ht) && ht->nNumUsed >= offset) { + Bucket *b = &ht->arData[offset - 1]; + if (b->key && zend_string_equals(b->key, Z_STR_P(dim))) { + ZVAL_COPY_DEREF(EX_VAR(opline->result.var), &b->val); + zval_ptr_dtor_nogc(EX_VAR(opline->op1.var)); + ZEND_VM_NEXT_OPCODE_CHECK_EXCEPTION(); + } + } + + zend_fetch_dimension_address_read_R_ex(container, dim, IS_CONST, CACHE_ADDR(opline->extended_value) OPLINE_CC EXECUTE_DATA_CC); + zval_ptr_dtor_nogc(EX_VAR(opline->op1.var)); + ZEND_VM_NEXT_OPCODE_CHECK_EXCEPTION(); + } else if (EXPECTED(Z_TYPE_P(container) == IS_REFERENCE)) { + container = Z_REFVAL_P(container); + if (EXPECTED(Z_TYPE_P(container) == IS_ARRAY)) { + goto fetch_dim_r_const_index_array; + } else { + goto fetch_dim_r_const_index_slow; + } + } else { +fetch_dim_r_const_index_slow: + if (IS_CONST == IS_CONST && Z_EXTRA_P(dim) == ZEND_EXTRA_VALUE) { + dim++; + } + zend_fetch_dimension_address_read_R_slow(container, dim OPLINE_CC EXECUTE_DATA_CC); + zval_ptr_dtor_nogc(EX_VAR(opline->op1.var)); + ZEND_VM_NEXT_OPCODE_CHECK_EXCEPTION(); + } + + ZVAL_NULL(EX_VAR(opline->result.var)); + zend_undefined_offset(offset); + zval_ptr_dtor_nogc(EX_VAR(opline->op1.var)); + ZEND_VM_NEXT_OPCODE_CHECK_EXCEPTION(); +} + static ZEND_VM_HOT ZEND_OPCODE_HANDLER_RET ZEND_FASTCALL ZEND_FETCH_DIM_R_INDEX_SPEC_TMPVAR_CONST_HANDLER(ZEND_OPCODE_HANDLER_ARGS) { USE_OPLINE @@ -45819,6 +45869,56 @@ static ZEND_OPCODE_HANDLER_RET ZEND_FASTCALL ZEND_IS_NOT_IDENTICAL_NOTHROW_SPEC_ ZEND_VM_SMART_BRANCH(!result, 0); } +static ZEND_VM_HOT ZEND_OPCODE_HANDLER_RET ZEND_FASTCALL ZEND_FETCH_DIM_R_STRING_INDEX_SPEC_CV_CONST_HANDLER(ZEND_OPCODE_HANDLER_ARGS) +{ + USE_OPLINE + SAVE_OPLINE(); + + zval *container, *dim; + zend_long offset; + HashTable *ht; + + container = EX_VAR(opline->op1.var); + dim = RT_CONSTANT(opline, opline->op2); + if (EXPECTED(Z_TYPE_P(container) == IS_ARRAY)) { +fetch_dim_r_const_index_array: + ht = Z_ARRVAL_P(container); + uintptr_t offset = (uintptr_t)CACHED_PTR(opline->extended_value); + if (offset && !HT_IS_PACKED(ht) && ht->nNumUsed >= offset) { + Bucket *b = &ht->arData[offset - 1]; + if (b->key && zend_string_equals(b->key, Z_STR_P(dim))) { + ZVAL_COPY_DEREF(EX_VAR(opline->result.var), &b->val); + + ZEND_VM_NEXT_OPCODE_CHECK_EXCEPTION(); + } + } + + zend_fetch_dimension_address_read_R_ex(container, dim, IS_CONST, CACHE_ADDR(opline->extended_value) OPLINE_CC EXECUTE_DATA_CC); + + ZEND_VM_NEXT_OPCODE_CHECK_EXCEPTION(); + } else if (EXPECTED(Z_TYPE_P(container) == IS_REFERENCE)) { + container = Z_REFVAL_P(container); + if (EXPECTED(Z_TYPE_P(container) == IS_ARRAY)) { + goto fetch_dim_r_const_index_array; + } else { + goto fetch_dim_r_const_index_slow; + } + } else { +fetch_dim_r_const_index_slow: + if (IS_CONST == IS_CONST && Z_EXTRA_P(dim) == ZEND_EXTRA_VALUE) { + dim++; + } + zend_fetch_dimension_address_read_R_slow(container, dim OPLINE_CC EXECUTE_DATA_CC); + + ZEND_VM_NEXT_OPCODE_CHECK_EXCEPTION(); + } + + ZVAL_NULL(EX_VAR(opline->result.var)); + zend_undefined_offset(offset); + + ZEND_VM_NEXT_OPCODE_CHECK_EXCEPTION(); +} + static ZEND_VM_HOT ZEND_OPCODE_HANDLER_RET ZEND_FASTCALL ZEND_FETCH_DIM_R_INDEX_SPEC_CV_CONST_HANDLER(ZEND_OPCODE_HANDLER_ARGS) { USE_OPLINE @@ -58483,6 +58583,11 @@ ZEND_API void execute_ex(zend_execute_data *ex) (void*)&&ZEND_NULL_LABEL, (void*)&&ZEND_QM_ASSIGN_NOREF_SPEC_TMPVARCV_LABEL, (void*)&&ZEND_NULL_LABEL, + (void*)&&ZEND_FETCH_DIM_R_STRING_INDEX_SPEC_TMPVAR_CONST_LABEL, + (void*)&&ZEND_FETCH_DIM_R_STRING_INDEX_SPEC_TMPVAR_CONST_LABEL, + (void*)&&ZEND_NULL_LABEL, + (void*)&&ZEND_FETCH_DIM_R_STRING_INDEX_SPEC_CV_CONST_LABEL, + (void*)&&ZEND_NULL_LABEL, (void*)&&ZEND_FETCH_DIM_R_INDEX_SPEC_CONST_TMPVARCV_LABEL, (void*)&&ZEND_FETCH_DIM_R_INDEX_SPEC_CONST_TMPVARCV_LABEL, (void*)&&ZEND_NULL_LABEL, @@ -60816,6 +60921,11 @@ ZEND_API void execute_ex(zend_execute_data *ex) ZEND_INSTANCEOF_SPEC_TMPVAR_CONST_HANDLER(ZEND_OPCODE_HANDLER_ARGS_PASSTHRU); VM_TRACE_OP_END(ZEND_INSTANCEOF_SPEC_TMPVAR_CONST) HYBRID_BREAK(); + HYBRID_CASE(ZEND_FETCH_DIM_R_STRING_INDEX_SPEC_TMPVAR_CONST): + VM_TRACE(ZEND_FETCH_DIM_R_STRING_INDEX_SPEC_TMPVAR_CONST) + ZEND_FETCH_DIM_R_STRING_INDEX_SPEC_TMPVAR_CONST_HANDLER(ZEND_OPCODE_HANDLER_ARGS_PASSTHRU); + VM_TRACE_OP_END(ZEND_FETCH_DIM_R_STRING_INDEX_SPEC_TMPVAR_CONST) + HYBRID_BREAK(); HYBRID_CASE(ZEND_FETCH_DIM_R_INDEX_SPEC_TMPVAR_CONST): VM_TRACE(ZEND_FETCH_DIM_R_INDEX_SPEC_TMPVAR_CONST) ZEND_FETCH_DIM_R_INDEX_SPEC_TMPVAR_CONST_HANDLER(ZEND_OPCODE_HANDLER_ARGS_PASSTHRU); @@ -63398,6 +63508,11 @@ ZEND_API void execute_ex(zend_execute_data *ex) ZEND_IS_NOT_IDENTICAL_NOTHROW_SPEC_CV_CONST_HANDLER(ZEND_OPCODE_HANDLER_ARGS_PASSTHRU); VM_TRACE_OP_END(ZEND_IS_NOT_IDENTICAL_NOTHROW_SPEC_CV_CONST) HYBRID_BREAK(); + HYBRID_CASE(ZEND_FETCH_DIM_R_STRING_INDEX_SPEC_CV_CONST): + VM_TRACE(ZEND_FETCH_DIM_R_STRING_INDEX_SPEC_CV_CONST) + ZEND_FETCH_DIM_R_STRING_INDEX_SPEC_CV_CONST_HANDLER(ZEND_OPCODE_HANDLER_ARGS_PASSTHRU); + VM_TRACE_OP_END(ZEND_FETCH_DIM_R_STRING_INDEX_SPEC_CV_CONST) + HYBRID_BREAK(); HYBRID_CASE(ZEND_FETCH_DIM_R_INDEX_SPEC_CV_CONST): VM_TRACE(ZEND_FETCH_DIM_R_INDEX_SPEC_CV_CONST) ZEND_FETCH_DIM_R_INDEX_SPEC_CV_CONST_HANDLER(ZEND_OPCODE_HANDLER_ARGS_PASSTHRU); @@ -67675,6 +67790,11 @@ void zend_vm_init(void) ZEND_NULL_HANDLER, ZEND_QM_ASSIGN_NOREF_SPEC_TMPVARCV_HANDLER, ZEND_NULL_HANDLER, + ZEND_FETCH_DIM_R_STRING_INDEX_SPEC_TMPVAR_CONST_HANDLER, + ZEND_FETCH_DIM_R_STRING_INDEX_SPEC_TMPVAR_CONST_HANDLER, + ZEND_NULL_HANDLER, + ZEND_FETCH_DIM_R_STRING_INDEX_SPEC_CV_CONST_HANDLER, + ZEND_NULL_HANDLER, ZEND_FETCH_DIM_R_INDEX_SPEC_CONST_TMPVARCV_HANDLER, ZEND_FETCH_DIM_R_INDEX_SPEC_CONST_TMPVARCV_HANDLER, ZEND_NULL_HANDLER, @@ -67761,7 +67881,7 @@ void zend_vm_init(void) 1255, 1256 | SPEC_RULE_OP1, 1261 | SPEC_RULE_OP1, - 3487, + 3492, 1266 | SPEC_RULE_OP1, 1271 | SPEC_RULE_OP1, 1276 | SPEC_RULE_OP2, @@ -67795,7 +67915,7 @@ void zend_vm_init(void) 1559 | SPEC_RULE_OP1 | SPEC_RULE_OP2, 1584 | SPEC_RULE_OP1, 1589, - 3487, + 3492, 1590 | SPEC_RULE_OP1, 1595 | SPEC_RULE_OP1 | SPEC_RULE_OP2, 1620 | SPEC_RULE_OP1 | SPEC_RULE_OP2, @@ -67927,51 +68047,51 @@ void zend_vm_init(void) 2575, 2576, 2577, - 3487, - 3487, - 3487, - 3487, - 3487, - 3487, - 3487, - 3487, - 3487, - 3487, - 3487, - 3487, - 3487, - 3487, - 3487, - 3487, - 3487, - 3487, - 3487, - 3487, - 3487, - 3487, - 3487, - 3487, - 3487, - 3487, - 3487, - 3487, - 3487, - 3487, - 3487, - 3487, - 3487, - 3487, - 3487, - 3487, - 3487, - 3487, - 3487, - 3487, - 3487, - 3487, - 3487, - 3487, - 3487, + 3492, + 3492, + 3492, + 3492, + 3492, + 3492, + 3492, + 3492, + 3492, + 3492, + 3492, + 3492, + 3492, + 3492, + 3492, + 3492, + 3492, + 3492, + 3492, + 3492, + 3492, + 3492, + 3492, + 3492, + 3492, + 3492, + 3492, + 3492, + 3492, + 3492, + 3492, + 3492, + 3492, + 3492, + 3492, + 3492, + 3492, + 3492, + 3492, + 3492, + 3492, + 3492, + 3492, + 3492, + 3492, }; #if (ZEND_VM_KIND == ZEND_VM_KIND_HYBRID) zend_opcode_handler_funcs = labels; @@ -68353,35 +68473,37 @@ 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 = 3483; + spec = 3488; } 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 = 3478 | SPEC_RULE_OP1; + spec = 3483 | SPEC_RULE_OP1; } break; case ZEND_FE_FETCH_R: if (op->op2_type == IS_CV && (op1_info & (MAY_BE_ANY|MAY_BE_REF)) == MAY_BE_ARRAY) { - spec = 3485 | SPEC_RULE_RETVAL; + spec = 3490 | SPEC_RULE_RETVAL; } break; case ZEND_FETCH_DIM_R: - if (!(op2_info & (MAY_BE_UNDEF|MAY_BE_NULL|MAY_BE_STRING|MAY_BE_ARRAY|MAY_BE_OBJECT|MAY_BE_RESOURCE|MAY_BE_REF))) { + if (op->op1_type != IS_CONST && op->op2_type == IS_CONST && !(op2_info & (MAY_BE_ANY-MAY_BE_STRING))) { + spec = 3448 | SPEC_RULE_OP1; + } else if (!(op2_info & (MAY_BE_UNDEF|MAY_BE_NULL|MAY_BE_STRING|MAY_BE_ARRAY|MAY_BE_OBJECT|MAY_BE_RESOURCE|MAY_BE_REF))) { if (op->op1_type == IS_CONST && op->op2_type == IS_CONST) { break; } - spec = 3448 | SPEC_RULE_OP1 | SPEC_RULE_OP2; + spec = 3453 | SPEC_RULE_OP1 | SPEC_RULE_OP2; } 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 = 3484; + spec = 3489; } break; case ZEND_SEND_VAR: if (op->op2_type == IS_UNUSED && (op1_info & (MAY_BE_UNDEF|MAY_BE_REF)) == 0) { - spec = 3473 | SPEC_RULE_OP1; + spec = 3478 | SPEC_RULE_OP1; } break; case ZEND_COUNT: diff --git a/Zend/zend_vm_handlers.h b/Zend/zend_vm_handlers.h index cbbc6a4772788..5f8b610f0184b 100644 --- a/Zend/zend_vm_handlers.h +++ b/Zend/zend_vm_handlers.h @@ -1848,27 +1848,30 @@ _(3444, ZEND_QM_ASSIGN_NOREF_SPEC_TMPVARCV) \ _(3445, ZEND_QM_ASSIGN_NOREF_SPEC_TMPVARCV) \ _(3447, ZEND_QM_ASSIGN_NOREF_SPEC_TMPVARCV) \ - _(3449, ZEND_FETCH_DIM_R_INDEX_SPEC_CONST_TMPVARCV) \ - _(3450, ZEND_FETCH_DIM_R_INDEX_SPEC_CONST_TMPVARCV) \ - _(3452, ZEND_FETCH_DIM_R_INDEX_SPEC_CONST_TMPVARCV) \ - _(3453, ZEND_FETCH_DIM_R_INDEX_SPEC_TMPVAR_CONST) \ - _(3454, ZEND_FETCH_DIM_R_INDEX_SPEC_TMPVAR_TMPVARCV) \ - _(3455, ZEND_FETCH_DIM_R_INDEX_SPEC_TMPVAR_TMPVARCV) \ - _(3457, ZEND_FETCH_DIM_R_INDEX_SPEC_TMPVAR_TMPVARCV) \ + _(3449, ZEND_FETCH_DIM_R_STRING_INDEX_SPEC_TMPVAR_CONST) \ + _(3450, ZEND_FETCH_DIM_R_STRING_INDEX_SPEC_TMPVAR_CONST) \ + _(3452, ZEND_FETCH_DIM_R_STRING_INDEX_SPEC_CV_CONST) \ + _(3454, ZEND_FETCH_DIM_R_INDEX_SPEC_CONST_TMPVARCV) \ + _(3455, ZEND_FETCH_DIM_R_INDEX_SPEC_CONST_TMPVARCV) \ + _(3457, ZEND_FETCH_DIM_R_INDEX_SPEC_CONST_TMPVARCV) \ _(3458, ZEND_FETCH_DIM_R_INDEX_SPEC_TMPVAR_CONST) \ _(3459, ZEND_FETCH_DIM_R_INDEX_SPEC_TMPVAR_TMPVARCV) \ _(3460, ZEND_FETCH_DIM_R_INDEX_SPEC_TMPVAR_TMPVARCV) \ _(3462, ZEND_FETCH_DIM_R_INDEX_SPEC_TMPVAR_TMPVARCV) \ - _(3468, ZEND_FETCH_DIM_R_INDEX_SPEC_CV_CONST) \ - _(3469, ZEND_FETCH_DIM_R_INDEX_SPEC_CV_TMPVARCV) \ - _(3470, ZEND_FETCH_DIM_R_INDEX_SPEC_CV_TMPVARCV) \ - _(3472, ZEND_FETCH_DIM_R_INDEX_SPEC_CV_TMPVARCV) \ - _(3475, ZEND_SEND_VAR_SIMPLE_SPEC_VAR) \ - _(3477, ZEND_SEND_VAR_SIMPLE_SPEC_CV) \ - _(3480, ZEND_SEND_VAR_EX_SIMPLE_SPEC_VAR_UNUSED) \ - _(3482, ZEND_SEND_VAR_EX_SIMPLE_SPEC_CV_UNUSED) \ - _(3483, ZEND_SEND_VAL_SIMPLE_SPEC_CONST) \ - _(3484, ZEND_SEND_VAL_EX_SIMPLE_SPEC_CONST) \ - _(3485, ZEND_FE_FETCH_R_SIMPLE_SPEC_VAR_CV_RETVAL_UNUSED) \ - _(3486, ZEND_FE_FETCH_R_SIMPLE_SPEC_VAR_CV_RETVAL_USED) \ - _(3486+1, ZEND_NULL) + _(3463, ZEND_FETCH_DIM_R_INDEX_SPEC_TMPVAR_CONST) \ + _(3464, ZEND_FETCH_DIM_R_INDEX_SPEC_TMPVAR_TMPVARCV) \ + _(3465, ZEND_FETCH_DIM_R_INDEX_SPEC_TMPVAR_TMPVARCV) \ + _(3467, ZEND_FETCH_DIM_R_INDEX_SPEC_TMPVAR_TMPVARCV) \ + _(3473, ZEND_FETCH_DIM_R_INDEX_SPEC_CV_CONST) \ + _(3474, ZEND_FETCH_DIM_R_INDEX_SPEC_CV_TMPVARCV) \ + _(3475, ZEND_FETCH_DIM_R_INDEX_SPEC_CV_TMPVARCV) \ + _(3477, ZEND_FETCH_DIM_R_INDEX_SPEC_CV_TMPVARCV) \ + _(3480, ZEND_SEND_VAR_SIMPLE_SPEC_VAR) \ + _(3482, ZEND_SEND_VAR_SIMPLE_SPEC_CV) \ + _(3485, ZEND_SEND_VAR_EX_SIMPLE_SPEC_VAR_UNUSED) \ + _(3487, ZEND_SEND_VAR_EX_SIMPLE_SPEC_CV_UNUSED) \ + _(3488, ZEND_SEND_VAL_SIMPLE_SPEC_CONST) \ + _(3489, ZEND_SEND_VAL_EX_SIMPLE_SPEC_CONST) \ + _(3490, ZEND_FE_FETCH_R_SIMPLE_SPEC_VAR_CV_RETVAL_UNUSED) \ + _(3491, ZEND_FE_FETCH_R_SIMPLE_SPEC_VAR_CV_RETVAL_USED) \ + _(3491+1, ZEND_NULL) From 55d44ee81e06aa22599a6a0e2f4d16081aa02f5e Mon Sep 17 00:00:00 2001 From: Ilija Tovilo Date: Mon, 5 May 2025 13:44:24 +0200 Subject: [PATCH 2/6] Drop dead code path --- Zend/zend_vm_def.h | 6 ------ Zend/zend_vm_execute.h | 12 ------------ 2 files changed, 18 deletions(-) diff --git a/Zend/zend_vm_def.h b/Zend/zend_vm_def.h index 3284138079099..d8859d2cfe16b 100644 --- a/Zend/zend_vm_def.h +++ b/Zend/zend_vm_def.h @@ -10271,7 +10271,6 @@ ZEND_VM_HOT_TYPE_SPEC_HANDLER(ZEND_FETCH_DIM_R, (op->op1_type != IS_CONST && op- SAVE_OPLINE(); zval *container, *dim; - zend_long offset; HashTable *ht; container = GET_OP1_ZVAL_PTR_UNDEF(BP_VAR_R); @@ -10308,11 +10307,6 @@ ZEND_VM_C_LABEL(fetch_dim_r_const_index_slow): FREE_OP1(); ZEND_VM_NEXT_OPCODE_CHECK_EXCEPTION(); } - - ZVAL_NULL(EX_VAR(opline->result.var)); - zend_undefined_offset(offset); - FREE_OP1(); - ZEND_VM_NEXT_OPCODE_CHECK_EXCEPTION(); } ZEND_VM_HOT_TYPE_SPEC_HANDLER(ZEND_FETCH_DIM_R, (!(op2_info & (MAY_BE_UNDEF|MAY_BE_NULL|MAY_BE_STRING|MAY_BE_ARRAY|MAY_BE_OBJECT|MAY_BE_RESOURCE|MAY_BE_REF))), ZEND_FETCH_DIM_R_INDEX, CONST|TMPVAR|CV, CONST|TMPVARCV, SPEC(NO_CONST_CONST)) diff --git a/Zend/zend_vm_execute.h b/Zend/zend_vm_execute.h index 2fba725ef3358..aedb9d088dbc8 100644 --- a/Zend/zend_vm_execute.h +++ b/Zend/zend_vm_execute.h @@ -17122,7 +17122,6 @@ static ZEND_VM_HOT ZEND_OPCODE_HANDLER_RET ZEND_FASTCALL ZEND_FETCH_DIM_R_STRING SAVE_OPLINE(); zval *container, *dim; - zend_long offset; HashTable *ht; container = _get_zval_ptr_var(opline->op1.var EXECUTE_DATA_CC); @@ -17159,11 +17158,6 @@ static ZEND_VM_HOT ZEND_OPCODE_HANDLER_RET ZEND_FASTCALL ZEND_FETCH_DIM_R_STRING zval_ptr_dtor_nogc(EX_VAR(opline->op1.var)); ZEND_VM_NEXT_OPCODE_CHECK_EXCEPTION(); } - - ZVAL_NULL(EX_VAR(opline->result.var)); - zend_undefined_offset(offset); - zval_ptr_dtor_nogc(EX_VAR(opline->op1.var)); - ZEND_VM_NEXT_OPCODE_CHECK_EXCEPTION(); } static ZEND_VM_HOT ZEND_OPCODE_HANDLER_RET ZEND_FASTCALL ZEND_FETCH_DIM_R_INDEX_SPEC_TMPVAR_CONST_HANDLER(ZEND_OPCODE_HANDLER_ARGS) @@ -45875,7 +45869,6 @@ static ZEND_VM_HOT ZEND_OPCODE_HANDLER_RET ZEND_FASTCALL ZEND_FETCH_DIM_R_STRING SAVE_OPLINE(); zval *container, *dim; - zend_long offset; HashTable *ht; container = EX_VAR(opline->op1.var); @@ -45912,11 +45905,6 @@ static ZEND_VM_HOT ZEND_OPCODE_HANDLER_RET ZEND_FASTCALL ZEND_FETCH_DIM_R_STRING ZEND_VM_NEXT_OPCODE_CHECK_EXCEPTION(); } - - ZVAL_NULL(EX_VAR(opline->result.var)); - zend_undefined_offset(offset); - - ZEND_VM_NEXT_OPCODE_CHECK_EXCEPTION(); } static ZEND_VM_HOT ZEND_OPCODE_HANDLER_RET ZEND_FASTCALL ZEND_FETCH_DIM_R_INDEX_SPEC_CV_CONST_HANDLER(ZEND_OPCODE_HANDLER_ARGS) From 77eebedec57e7e0993f3f13f20aa557eac5fa66a Mon Sep 17 00:00:00 2001 From: Ilija Tovilo Date: Mon, 5 May 2025 13:47:05 +0200 Subject: [PATCH 3/6] Add support for int dim --- Zend/zend_vm_def.h | 45 +++++++++++---- Zend/zend_vm_execute.h | 120 +++++++++++++++++++++++++++------------- Zend/zend_vm_handlers.h | 6 +- 3 files changed, 120 insertions(+), 51 deletions(-) diff --git a/Zend/zend_vm_def.h b/Zend/zend_vm_def.h index d8859d2cfe16b..809a287f34381 100644 --- a/Zend/zend_vm_def.h +++ b/Zend/zend_vm_def.h @@ -10265,23 +10265,41 @@ ZEND_VM_HOT_TYPE_SPEC_HANDLER(ZEND_QM_ASSIGN, ((op->op1_type == IS_CONST) ? !Z_R ZEND_VM_NEXT_OPCODE(); } -ZEND_VM_HOT_TYPE_SPEC_HANDLER(ZEND_FETCH_DIM_R, (op->op1_type != IS_CONST && op->op2_type == IS_CONST && !(op2_info & (MAY_BE_ANY-MAY_BE_STRING))), ZEND_FETCH_DIM_R_STRING_INDEX, TMPVAR|CV, CONST, CACHE_SLOT) +ZEND_VM_HOT_TYPE_SPEC_HANDLER(ZEND_FETCH_DIM_R, (op->op1_type != IS_CONST && op->op2_type == IS_CONST && !(op2_info & (MAY_BE_ANY-MAY_BE_STRING-MAY_BE_LONG))), ZEND_FETCH_DIM_R_CACHED_INDEX, TMPVAR|CV, CONST, CACHE_SLOT) { USE_OPLINE SAVE_OPLINE(); - zval *container, *dim; - HashTable *ht; - - container = GET_OP1_ZVAL_PTR_UNDEF(BP_VAR_R); - dim = GET_OP2_ZVAL_PTR_UNDEF(BP_VAR_R); + zval *container = GET_OP1_ZVAL_PTR_UNDEF(BP_VAR_R); + zval *dim = GET_OP2_ZVAL_PTR_UNDEF(BP_VAR_R); if (EXPECTED(Z_TYPE_P(container) == IS_ARRAY)) { ZEND_VM_C_LABEL(fetch_dim_r_const_index_array): - ht = Z_ARRVAL_P(container); - uintptr_t offset = (uintptr_t)CACHED_PTR(opline->extended_value); - if (offset && !HT_IS_PACKED(ht) && ht->nNumUsed >= offset) { - Bucket *b = &ht->arData[offset - 1]; - if (b->key && zend_string_equals(b->key, Z_STR_P(dim))) { + HashTable *ht = Z_ARRVAL_P(container); + if (Z_TYPE_P(dim) == IS_LONG) { + zend_long offset = Z_LVAL_P(dim); + if (HT_IS_PACKED(ht)) { + if (EXPECTED((zend_ulong)offset < (zend_ulong)ht->nNumUsed)) { + zval *value = &ht->arPacked[offset]; + if (EXPECTED(Z_TYPE_P(value) != IS_UNDEF)) { + ZVAL_COPY_DEREF(EX_VAR(opline->result.var), value); + FREE_OP1(); + ZEND_VM_NEXT_OPCODE_CHECK_EXCEPTION(); + } + } + zend_undefined_offset(offset); + ZEND_VM_C_GOTO(fetch_dim_r_cached_index_undef); + } + } else { + if (HT_IS_PACKED(ht)) { + zend_undefined_index(Z_STR_P(dim)); + ZEND_VM_C_GOTO(fetch_dim_r_cached_index_undef); + } + } + + uintptr_t cached_offset = (uintptr_t)CACHED_PTR(opline->extended_value); + if (cached_offset && ht->nNumUsed >= cached_offset) { + Bucket *b = &ht->arData[cached_offset - 1]; + if (!b->key ? (Z_TYPE_P(dim) == IS_LONG && b->h == Z_LVAL_P(dim)) : (Z_TYPE_P(dim) == IS_STRING && zend_string_equals(b->key, Z_STR_P(dim)))) { ZVAL_COPY_DEREF(EX_VAR(opline->result.var), &b->val); FREE_OP1(); ZEND_VM_NEXT_OPCODE_CHECK_EXCEPTION(); @@ -10307,6 +10325,11 @@ ZEND_VM_C_LABEL(fetch_dim_r_const_index_slow): FREE_OP1(); ZEND_VM_NEXT_OPCODE_CHECK_EXCEPTION(); } + +ZEND_VM_C_LABEL(fetch_dim_r_cached_index_undef): + ZVAL_NULL(EX_VAR(opline->result.var)); + FREE_OP1(); + ZEND_VM_NEXT_OPCODE_CHECK_EXCEPTION(); } ZEND_VM_HOT_TYPE_SPEC_HANDLER(ZEND_FETCH_DIM_R, (!(op2_info & (MAY_BE_UNDEF|MAY_BE_NULL|MAY_BE_STRING|MAY_BE_ARRAY|MAY_BE_OBJECT|MAY_BE_RESOURCE|MAY_BE_REF))), ZEND_FETCH_DIM_R_INDEX, CONST|TMPVAR|CV, CONST|TMPVARCV, SPEC(NO_CONST_CONST)) diff --git a/Zend/zend_vm_execute.h b/Zend/zend_vm_execute.h index aedb9d088dbc8..0c3bc5a655d21 100644 --- a/Zend/zend_vm_execute.h +++ b/Zend/zend_vm_execute.h @@ -17116,23 +17116,41 @@ static ZEND_OPCODE_HANDLER_RET ZEND_FASTCALL ZEND_INSTANCEOF_SPEC_TMPVAR_CONST_H ZEND_VM_SMART_BRANCH(result, 1); } -static ZEND_VM_HOT ZEND_OPCODE_HANDLER_RET ZEND_FASTCALL ZEND_FETCH_DIM_R_STRING_INDEX_SPEC_TMPVAR_CONST_HANDLER(ZEND_OPCODE_HANDLER_ARGS) +static ZEND_VM_HOT ZEND_OPCODE_HANDLER_RET ZEND_FASTCALL ZEND_FETCH_DIM_R_CACHED_INDEX_SPEC_TMPVAR_CONST_HANDLER(ZEND_OPCODE_HANDLER_ARGS) { USE_OPLINE SAVE_OPLINE(); - zval *container, *dim; - HashTable *ht; - - container = _get_zval_ptr_var(opline->op1.var EXECUTE_DATA_CC); - dim = RT_CONSTANT(opline, opline->op2); + zval *container = _get_zval_ptr_var(opline->op1.var EXECUTE_DATA_CC); + zval *dim = RT_CONSTANT(opline, opline->op2); if (EXPECTED(Z_TYPE_P(container) == IS_ARRAY)) { fetch_dim_r_const_index_array: - ht = Z_ARRVAL_P(container); - uintptr_t offset = (uintptr_t)CACHED_PTR(opline->extended_value); - if (offset && !HT_IS_PACKED(ht) && ht->nNumUsed >= offset) { - Bucket *b = &ht->arData[offset - 1]; - if (b->key && zend_string_equals(b->key, Z_STR_P(dim))) { + HashTable *ht = Z_ARRVAL_P(container); + if (Z_TYPE_P(dim) == IS_LONG) { + zend_long offset = Z_LVAL_P(dim); + if (HT_IS_PACKED(ht)) { + if (EXPECTED((zend_ulong)offset < (zend_ulong)ht->nNumUsed)) { + zval *value = &ht->arPacked[offset]; + if (EXPECTED(Z_TYPE_P(value) != IS_UNDEF)) { + ZVAL_COPY_DEREF(EX_VAR(opline->result.var), value); + zval_ptr_dtor_nogc(EX_VAR(opline->op1.var)); + ZEND_VM_NEXT_OPCODE_CHECK_EXCEPTION(); + } + } + zend_undefined_offset(offset); + goto fetch_dim_r_cached_index_undef; + } + } else { + if (HT_IS_PACKED(ht)) { + zend_undefined_index(Z_STR_P(dim)); + goto fetch_dim_r_cached_index_undef; + } + } + + uintptr_t cached_offset = (uintptr_t)CACHED_PTR(opline->extended_value); + if (cached_offset && ht->nNumUsed >= cached_offset) { + Bucket *b = &ht->arData[cached_offset - 1]; + if (!b->key ? (Z_TYPE_P(dim) == IS_LONG && b->h == Z_LVAL_P(dim)) : (Z_TYPE_P(dim) == IS_STRING && zend_string_equals(b->key, Z_STR_P(dim)))) { ZVAL_COPY_DEREF(EX_VAR(opline->result.var), &b->val); zval_ptr_dtor_nogc(EX_VAR(opline->op1.var)); ZEND_VM_NEXT_OPCODE_CHECK_EXCEPTION(); @@ -17158,6 +17176,11 @@ static ZEND_VM_HOT ZEND_OPCODE_HANDLER_RET ZEND_FASTCALL ZEND_FETCH_DIM_R_STRING zval_ptr_dtor_nogc(EX_VAR(opline->op1.var)); ZEND_VM_NEXT_OPCODE_CHECK_EXCEPTION(); } + +fetch_dim_r_cached_index_undef: + ZVAL_NULL(EX_VAR(opline->result.var)); + zval_ptr_dtor_nogc(EX_VAR(opline->op1.var)); + ZEND_VM_NEXT_OPCODE_CHECK_EXCEPTION(); } static ZEND_VM_HOT ZEND_OPCODE_HANDLER_RET ZEND_FASTCALL ZEND_FETCH_DIM_R_INDEX_SPEC_TMPVAR_CONST_HANDLER(ZEND_OPCODE_HANDLER_ARGS) @@ -45863,23 +45886,41 @@ static ZEND_OPCODE_HANDLER_RET ZEND_FASTCALL ZEND_IS_NOT_IDENTICAL_NOTHROW_SPEC_ ZEND_VM_SMART_BRANCH(!result, 0); } -static ZEND_VM_HOT ZEND_OPCODE_HANDLER_RET ZEND_FASTCALL ZEND_FETCH_DIM_R_STRING_INDEX_SPEC_CV_CONST_HANDLER(ZEND_OPCODE_HANDLER_ARGS) +static ZEND_VM_HOT ZEND_OPCODE_HANDLER_RET ZEND_FASTCALL ZEND_FETCH_DIM_R_CACHED_INDEX_SPEC_CV_CONST_HANDLER(ZEND_OPCODE_HANDLER_ARGS) { USE_OPLINE SAVE_OPLINE(); - zval *container, *dim; - HashTable *ht; - - container = EX_VAR(opline->op1.var); - dim = RT_CONSTANT(opline, opline->op2); + zval *container = EX_VAR(opline->op1.var); + zval *dim = RT_CONSTANT(opline, opline->op2); if (EXPECTED(Z_TYPE_P(container) == IS_ARRAY)) { fetch_dim_r_const_index_array: - ht = Z_ARRVAL_P(container); - uintptr_t offset = (uintptr_t)CACHED_PTR(opline->extended_value); - if (offset && !HT_IS_PACKED(ht) && ht->nNumUsed >= offset) { - Bucket *b = &ht->arData[offset - 1]; - if (b->key && zend_string_equals(b->key, Z_STR_P(dim))) { + HashTable *ht = Z_ARRVAL_P(container); + if (Z_TYPE_P(dim) == IS_LONG) { + zend_long offset = Z_LVAL_P(dim); + if (HT_IS_PACKED(ht)) { + if (EXPECTED((zend_ulong)offset < (zend_ulong)ht->nNumUsed)) { + zval *value = &ht->arPacked[offset]; + if (EXPECTED(Z_TYPE_P(value) != IS_UNDEF)) { + ZVAL_COPY_DEREF(EX_VAR(opline->result.var), value); + + ZEND_VM_NEXT_OPCODE_CHECK_EXCEPTION(); + } + } + zend_undefined_offset(offset); + goto fetch_dim_r_cached_index_undef; + } + } else { + if (HT_IS_PACKED(ht)) { + zend_undefined_index(Z_STR_P(dim)); + goto fetch_dim_r_cached_index_undef; + } + } + + uintptr_t cached_offset = (uintptr_t)CACHED_PTR(opline->extended_value); + if (cached_offset && ht->nNumUsed >= cached_offset) { + Bucket *b = &ht->arData[cached_offset - 1]; + if (!b->key ? (Z_TYPE_P(dim) == IS_LONG && b->h == Z_LVAL_P(dim)) : (Z_TYPE_P(dim) == IS_STRING && zend_string_equals(b->key, Z_STR_P(dim)))) { ZVAL_COPY_DEREF(EX_VAR(opline->result.var), &b->val); ZEND_VM_NEXT_OPCODE_CHECK_EXCEPTION(); @@ -45905,6 +45946,11 @@ static ZEND_VM_HOT ZEND_OPCODE_HANDLER_RET ZEND_FASTCALL ZEND_FETCH_DIM_R_STRING ZEND_VM_NEXT_OPCODE_CHECK_EXCEPTION(); } + +fetch_dim_r_cached_index_undef: + ZVAL_NULL(EX_VAR(opline->result.var)); + + ZEND_VM_NEXT_OPCODE_CHECK_EXCEPTION(); } static ZEND_VM_HOT ZEND_OPCODE_HANDLER_RET ZEND_FASTCALL ZEND_FETCH_DIM_R_INDEX_SPEC_CV_CONST_HANDLER(ZEND_OPCODE_HANDLER_ARGS) @@ -58571,10 +58617,10 @@ ZEND_API void execute_ex(zend_execute_data *ex) (void*)&&ZEND_NULL_LABEL, (void*)&&ZEND_QM_ASSIGN_NOREF_SPEC_TMPVARCV_LABEL, (void*)&&ZEND_NULL_LABEL, - (void*)&&ZEND_FETCH_DIM_R_STRING_INDEX_SPEC_TMPVAR_CONST_LABEL, - (void*)&&ZEND_FETCH_DIM_R_STRING_INDEX_SPEC_TMPVAR_CONST_LABEL, + (void*)&&ZEND_FETCH_DIM_R_CACHED_INDEX_SPEC_TMPVAR_CONST_LABEL, + (void*)&&ZEND_FETCH_DIM_R_CACHED_INDEX_SPEC_TMPVAR_CONST_LABEL, (void*)&&ZEND_NULL_LABEL, - (void*)&&ZEND_FETCH_DIM_R_STRING_INDEX_SPEC_CV_CONST_LABEL, + (void*)&&ZEND_FETCH_DIM_R_CACHED_INDEX_SPEC_CV_CONST_LABEL, (void*)&&ZEND_NULL_LABEL, (void*)&&ZEND_FETCH_DIM_R_INDEX_SPEC_CONST_TMPVARCV_LABEL, (void*)&&ZEND_FETCH_DIM_R_INDEX_SPEC_CONST_TMPVARCV_LABEL, @@ -60909,10 +60955,10 @@ ZEND_API void execute_ex(zend_execute_data *ex) ZEND_INSTANCEOF_SPEC_TMPVAR_CONST_HANDLER(ZEND_OPCODE_HANDLER_ARGS_PASSTHRU); VM_TRACE_OP_END(ZEND_INSTANCEOF_SPEC_TMPVAR_CONST) HYBRID_BREAK(); - HYBRID_CASE(ZEND_FETCH_DIM_R_STRING_INDEX_SPEC_TMPVAR_CONST): - VM_TRACE(ZEND_FETCH_DIM_R_STRING_INDEX_SPEC_TMPVAR_CONST) - ZEND_FETCH_DIM_R_STRING_INDEX_SPEC_TMPVAR_CONST_HANDLER(ZEND_OPCODE_HANDLER_ARGS_PASSTHRU); - VM_TRACE_OP_END(ZEND_FETCH_DIM_R_STRING_INDEX_SPEC_TMPVAR_CONST) + HYBRID_CASE(ZEND_FETCH_DIM_R_CACHED_INDEX_SPEC_TMPVAR_CONST): + VM_TRACE(ZEND_FETCH_DIM_R_CACHED_INDEX_SPEC_TMPVAR_CONST) + ZEND_FETCH_DIM_R_CACHED_INDEX_SPEC_TMPVAR_CONST_HANDLER(ZEND_OPCODE_HANDLER_ARGS_PASSTHRU); + VM_TRACE_OP_END(ZEND_FETCH_DIM_R_CACHED_INDEX_SPEC_TMPVAR_CONST) HYBRID_BREAK(); HYBRID_CASE(ZEND_FETCH_DIM_R_INDEX_SPEC_TMPVAR_CONST): VM_TRACE(ZEND_FETCH_DIM_R_INDEX_SPEC_TMPVAR_CONST) @@ -63496,10 +63542,10 @@ ZEND_API void execute_ex(zend_execute_data *ex) ZEND_IS_NOT_IDENTICAL_NOTHROW_SPEC_CV_CONST_HANDLER(ZEND_OPCODE_HANDLER_ARGS_PASSTHRU); VM_TRACE_OP_END(ZEND_IS_NOT_IDENTICAL_NOTHROW_SPEC_CV_CONST) HYBRID_BREAK(); - HYBRID_CASE(ZEND_FETCH_DIM_R_STRING_INDEX_SPEC_CV_CONST): - VM_TRACE(ZEND_FETCH_DIM_R_STRING_INDEX_SPEC_CV_CONST) - ZEND_FETCH_DIM_R_STRING_INDEX_SPEC_CV_CONST_HANDLER(ZEND_OPCODE_HANDLER_ARGS_PASSTHRU); - VM_TRACE_OP_END(ZEND_FETCH_DIM_R_STRING_INDEX_SPEC_CV_CONST) + HYBRID_CASE(ZEND_FETCH_DIM_R_CACHED_INDEX_SPEC_CV_CONST): + VM_TRACE(ZEND_FETCH_DIM_R_CACHED_INDEX_SPEC_CV_CONST) + ZEND_FETCH_DIM_R_CACHED_INDEX_SPEC_CV_CONST_HANDLER(ZEND_OPCODE_HANDLER_ARGS_PASSTHRU); + VM_TRACE_OP_END(ZEND_FETCH_DIM_R_CACHED_INDEX_SPEC_CV_CONST) HYBRID_BREAK(); HYBRID_CASE(ZEND_FETCH_DIM_R_INDEX_SPEC_CV_CONST): VM_TRACE(ZEND_FETCH_DIM_R_INDEX_SPEC_CV_CONST) @@ -67778,10 +67824,10 @@ void zend_vm_init(void) ZEND_NULL_HANDLER, ZEND_QM_ASSIGN_NOREF_SPEC_TMPVARCV_HANDLER, ZEND_NULL_HANDLER, - ZEND_FETCH_DIM_R_STRING_INDEX_SPEC_TMPVAR_CONST_HANDLER, - ZEND_FETCH_DIM_R_STRING_INDEX_SPEC_TMPVAR_CONST_HANDLER, + ZEND_FETCH_DIM_R_CACHED_INDEX_SPEC_TMPVAR_CONST_HANDLER, + ZEND_FETCH_DIM_R_CACHED_INDEX_SPEC_TMPVAR_CONST_HANDLER, ZEND_NULL_HANDLER, - ZEND_FETCH_DIM_R_STRING_INDEX_SPEC_CV_CONST_HANDLER, + ZEND_FETCH_DIM_R_CACHED_INDEX_SPEC_CV_CONST_HANDLER, ZEND_NULL_HANDLER, ZEND_FETCH_DIM_R_INDEX_SPEC_CONST_TMPVARCV_HANDLER, ZEND_FETCH_DIM_R_INDEX_SPEC_CONST_TMPVARCV_HANDLER, @@ -68475,7 +68521,7 @@ ZEND_API void ZEND_FASTCALL zend_vm_set_opcode_handler_ex(zend_op* op, uint32_t } break; case ZEND_FETCH_DIM_R: - if (op->op1_type != IS_CONST && op->op2_type == IS_CONST && !(op2_info & (MAY_BE_ANY-MAY_BE_STRING))) { + if (op->op1_type != IS_CONST && op->op2_type == IS_CONST && !(op2_info & (MAY_BE_ANY-MAY_BE_STRING-MAY_BE_LONG))) { spec = 3448 | SPEC_RULE_OP1; } else if (!(op2_info & (MAY_BE_UNDEF|MAY_BE_NULL|MAY_BE_STRING|MAY_BE_ARRAY|MAY_BE_OBJECT|MAY_BE_RESOURCE|MAY_BE_REF))) { if (op->op1_type == IS_CONST && op->op2_type == IS_CONST) { diff --git a/Zend/zend_vm_handlers.h b/Zend/zend_vm_handlers.h index 5f8b610f0184b..f3b0455ff55ad 100644 --- a/Zend/zend_vm_handlers.h +++ b/Zend/zend_vm_handlers.h @@ -1848,9 +1848,9 @@ _(3444, ZEND_QM_ASSIGN_NOREF_SPEC_TMPVARCV) \ _(3445, ZEND_QM_ASSIGN_NOREF_SPEC_TMPVARCV) \ _(3447, ZEND_QM_ASSIGN_NOREF_SPEC_TMPVARCV) \ - _(3449, ZEND_FETCH_DIM_R_STRING_INDEX_SPEC_TMPVAR_CONST) \ - _(3450, ZEND_FETCH_DIM_R_STRING_INDEX_SPEC_TMPVAR_CONST) \ - _(3452, ZEND_FETCH_DIM_R_STRING_INDEX_SPEC_CV_CONST) \ + _(3449, ZEND_FETCH_DIM_R_CACHED_INDEX_SPEC_TMPVAR_CONST) \ + _(3450, ZEND_FETCH_DIM_R_CACHED_INDEX_SPEC_TMPVAR_CONST) \ + _(3452, ZEND_FETCH_DIM_R_CACHED_INDEX_SPEC_CV_CONST) \ _(3454, ZEND_FETCH_DIM_R_INDEX_SPEC_CONST_TMPVARCV) \ _(3455, ZEND_FETCH_DIM_R_INDEX_SPEC_CONST_TMPVARCV) \ _(3457, ZEND_FETCH_DIM_R_INDEX_SPEC_CONST_TMPVARCV) \ From 798c58a0942be5d977699e87e5c3f66cb882cfd6 Mon Sep 17 00:00:00 2001 From: Ilija Tovilo Date: Mon, 5 May 2025 14:18:27 +0200 Subject: [PATCH 4/6] Avoid unnecessary SAVE_OPLINE and CHECK_EXCEPTION --- Zend/zend_vm_def.h | 23 +++++++++++++++++------ Zend/zend_vm_execute.h | 42 ++++++++++++++++++++++++++++++++---------- 2 files changed, 49 insertions(+), 16 deletions(-) diff --git a/Zend/zend_vm_def.h b/Zend/zend_vm_def.h index 809a287f34381..966a84709a225 100644 --- a/Zend/zend_vm_def.h +++ b/Zend/zend_vm_def.h @@ -10268,7 +10268,6 @@ ZEND_VM_HOT_TYPE_SPEC_HANDLER(ZEND_QM_ASSIGN, ((op->op1_type == IS_CONST) ? !Z_R ZEND_VM_HOT_TYPE_SPEC_HANDLER(ZEND_FETCH_DIM_R, (op->op1_type != IS_CONST && op->op2_type == IS_CONST && !(op2_info & (MAY_BE_ANY-MAY_BE_STRING-MAY_BE_LONG))), ZEND_FETCH_DIM_R_CACHED_INDEX, TMPVAR|CV, CONST, CACHE_SLOT) { USE_OPLINE - SAVE_OPLINE(); zval *container = GET_OP1_ZVAL_PTR_UNDEF(BP_VAR_R); zval *dim = GET_OP2_ZVAL_PTR_UNDEF(BP_VAR_R); @@ -10282,15 +10281,22 @@ ZEND_VM_C_LABEL(fetch_dim_r_const_index_array): zval *value = &ht->arPacked[offset]; if (EXPECTED(Z_TYPE_P(value) != IS_UNDEF)) { ZVAL_COPY_DEREF(EX_VAR(opline->result.var), value); - FREE_OP1(); - ZEND_VM_NEXT_OPCODE_CHECK_EXCEPTION(); + if (OP1_TYPE & (IS_TMP_VAR|IS_VAR)) { + SAVE_OPLINE(); + FREE_OP1(); + ZEND_VM_NEXT_OPCODE_CHECK_EXCEPTION(); + } else { + ZEND_VM_NEXT_OPCODE(); + } } } + SAVE_OPLINE(); zend_undefined_offset(offset); ZEND_VM_C_GOTO(fetch_dim_r_cached_index_undef); } } else { - if (HT_IS_PACKED(ht)) { + if (UNEXPECTED(HT_IS_PACKED(ht))) { + SAVE_OPLINE(); zend_undefined_index(Z_STR_P(dim)); ZEND_VM_C_GOTO(fetch_dim_r_cached_index_undef); } @@ -10301,11 +10307,16 @@ ZEND_VM_C_LABEL(fetch_dim_r_const_index_array): Bucket *b = &ht->arData[cached_offset - 1]; if (!b->key ? (Z_TYPE_P(dim) == IS_LONG && b->h == Z_LVAL_P(dim)) : (Z_TYPE_P(dim) == IS_STRING && zend_string_equals(b->key, Z_STR_P(dim)))) { ZVAL_COPY_DEREF(EX_VAR(opline->result.var), &b->val); - FREE_OP1(); - ZEND_VM_NEXT_OPCODE_CHECK_EXCEPTION(); + if (OP1_TYPE & (IS_TMP_VAR|IS_VAR)) { + FREE_OP1(); + ZEND_VM_NEXT_OPCODE_CHECK_EXCEPTION(); + } else { + ZEND_VM_NEXT_OPCODE(); + } } } + SAVE_OPLINE(); zend_fetch_dimension_address_read_R_ex(container, dim, OP2_TYPE, CACHE_ADDR(opline->extended_value) OPLINE_CC EXECUTE_DATA_CC); FREE_OP1(); ZEND_VM_NEXT_OPCODE_CHECK_EXCEPTION(); diff --git a/Zend/zend_vm_execute.h b/Zend/zend_vm_execute.h index 0c3bc5a655d21..b59cb356e9242 100644 --- a/Zend/zend_vm_execute.h +++ b/Zend/zend_vm_execute.h @@ -17119,7 +17119,6 @@ static ZEND_OPCODE_HANDLER_RET ZEND_FASTCALL ZEND_INSTANCEOF_SPEC_TMPVAR_CONST_H static ZEND_VM_HOT ZEND_OPCODE_HANDLER_RET ZEND_FASTCALL ZEND_FETCH_DIM_R_CACHED_INDEX_SPEC_TMPVAR_CONST_HANDLER(ZEND_OPCODE_HANDLER_ARGS) { USE_OPLINE - SAVE_OPLINE(); zval *container = _get_zval_ptr_var(opline->op1.var EXECUTE_DATA_CC); zval *dim = RT_CONSTANT(opline, opline->op2); @@ -17133,15 +17132,22 @@ static ZEND_VM_HOT ZEND_OPCODE_HANDLER_RET ZEND_FASTCALL ZEND_FETCH_DIM_R_CACHED zval *value = &ht->arPacked[offset]; if (EXPECTED(Z_TYPE_P(value) != IS_UNDEF)) { ZVAL_COPY_DEREF(EX_VAR(opline->result.var), value); - zval_ptr_dtor_nogc(EX_VAR(opline->op1.var)); - ZEND_VM_NEXT_OPCODE_CHECK_EXCEPTION(); + if ((IS_TMP_VAR|IS_VAR) & (IS_TMP_VAR|IS_VAR)) { + SAVE_OPLINE(); + zval_ptr_dtor_nogc(EX_VAR(opline->op1.var)); + ZEND_VM_NEXT_OPCODE_CHECK_EXCEPTION(); + } else { + ZEND_VM_NEXT_OPCODE(); + } } } + SAVE_OPLINE(); zend_undefined_offset(offset); goto fetch_dim_r_cached_index_undef; } } else { - if (HT_IS_PACKED(ht)) { + if (UNEXPECTED(HT_IS_PACKED(ht))) { + SAVE_OPLINE(); zend_undefined_index(Z_STR_P(dim)); goto fetch_dim_r_cached_index_undef; } @@ -17152,11 +17158,16 @@ static ZEND_VM_HOT ZEND_OPCODE_HANDLER_RET ZEND_FASTCALL ZEND_FETCH_DIM_R_CACHED Bucket *b = &ht->arData[cached_offset - 1]; if (!b->key ? (Z_TYPE_P(dim) == IS_LONG && b->h == Z_LVAL_P(dim)) : (Z_TYPE_P(dim) == IS_STRING && zend_string_equals(b->key, Z_STR_P(dim)))) { ZVAL_COPY_DEREF(EX_VAR(opline->result.var), &b->val); - zval_ptr_dtor_nogc(EX_VAR(opline->op1.var)); - ZEND_VM_NEXT_OPCODE_CHECK_EXCEPTION(); + if ((IS_TMP_VAR|IS_VAR) & (IS_TMP_VAR|IS_VAR)) { + zval_ptr_dtor_nogc(EX_VAR(opline->op1.var)); + ZEND_VM_NEXT_OPCODE_CHECK_EXCEPTION(); + } else { + ZEND_VM_NEXT_OPCODE(); + } } } + SAVE_OPLINE(); zend_fetch_dimension_address_read_R_ex(container, dim, IS_CONST, CACHE_ADDR(opline->extended_value) OPLINE_CC EXECUTE_DATA_CC); zval_ptr_dtor_nogc(EX_VAR(opline->op1.var)); ZEND_VM_NEXT_OPCODE_CHECK_EXCEPTION(); @@ -45889,7 +45900,6 @@ static ZEND_OPCODE_HANDLER_RET ZEND_FASTCALL ZEND_IS_NOT_IDENTICAL_NOTHROW_SPEC_ static ZEND_VM_HOT ZEND_OPCODE_HANDLER_RET ZEND_FASTCALL ZEND_FETCH_DIM_R_CACHED_INDEX_SPEC_CV_CONST_HANDLER(ZEND_OPCODE_HANDLER_ARGS) { USE_OPLINE - SAVE_OPLINE(); zval *container = EX_VAR(opline->op1.var); zval *dim = RT_CONSTANT(opline, opline->op2); @@ -45903,15 +45913,22 @@ static ZEND_VM_HOT ZEND_OPCODE_HANDLER_RET ZEND_FASTCALL ZEND_FETCH_DIM_R_CACHED zval *value = &ht->arPacked[offset]; if (EXPECTED(Z_TYPE_P(value) != IS_UNDEF)) { ZVAL_COPY_DEREF(EX_VAR(opline->result.var), value); + if (IS_CV & (IS_TMP_VAR|IS_VAR)) { + SAVE_OPLINE(); - ZEND_VM_NEXT_OPCODE_CHECK_EXCEPTION(); + ZEND_VM_NEXT_OPCODE_CHECK_EXCEPTION(); + } else { + ZEND_VM_NEXT_OPCODE(); + } } } + SAVE_OPLINE(); zend_undefined_offset(offset); goto fetch_dim_r_cached_index_undef; } } else { - if (HT_IS_PACKED(ht)) { + if (UNEXPECTED(HT_IS_PACKED(ht))) { + SAVE_OPLINE(); zend_undefined_index(Z_STR_P(dim)); goto fetch_dim_r_cached_index_undef; } @@ -45922,11 +45939,16 @@ static ZEND_VM_HOT ZEND_OPCODE_HANDLER_RET ZEND_FASTCALL ZEND_FETCH_DIM_R_CACHED Bucket *b = &ht->arData[cached_offset - 1]; if (!b->key ? (Z_TYPE_P(dim) == IS_LONG && b->h == Z_LVAL_P(dim)) : (Z_TYPE_P(dim) == IS_STRING && zend_string_equals(b->key, Z_STR_P(dim)))) { ZVAL_COPY_DEREF(EX_VAR(opline->result.var), &b->val); + if (IS_CV & (IS_TMP_VAR|IS_VAR)) { - ZEND_VM_NEXT_OPCODE_CHECK_EXCEPTION(); + ZEND_VM_NEXT_OPCODE_CHECK_EXCEPTION(); + } else { + ZEND_VM_NEXT_OPCODE(); + } } } + SAVE_OPLINE(); zend_fetch_dimension_address_read_R_ex(container, dim, IS_CONST, CACHE_ADDR(opline->extended_value) OPLINE_CC EXECUTE_DATA_CC); ZEND_VM_NEXT_OPCODE_CHECK_EXCEPTION(); From ebda10badfd6497e2b3387388b356744b9744680 Mon Sep 17 00:00:00 2001 From: Ilija Tovilo Date: Mon, 5 May 2025 16:05:06 +0200 Subject: [PATCH 5/6] Inline array operations --- Zend/zend_execute.c | 23 +++----- Zend/zend_vm_def.h | 60 +++++++++++++-------- Zend/zend_vm_execute.h | 120 ++++++++++++++++++++++++++--------------- 3 files changed, 120 insertions(+), 83 deletions(-) diff --git a/Zend/zend_execute.c b/Zend/zend_execute.c index 71994719f5970..0fbfdfa07ef04 100644 --- a/Zend/zend_execute.c +++ b/Zend/zend_execute.c @@ -2996,7 +2996,7 @@ static zend_never_inline void ZEND_FASTCALL zend_fetch_dimension_address_UNSET(z zend_fetch_dimension_address(result, container_ptr, dim, dim_type, BP_VAR_UNSET EXECUTE_DATA_CC); } -static zend_always_inline void zend_fetch_dimension_address_read(zval *result, zval *container, zval *dim, int dim_type, int type, bool is_list, int slow, void **cache_slot EXECUTE_DATA_DC) +static zend_always_inline void zend_fetch_dimension_address_read(zval *result, zval *container, zval *dim, int dim_type, int type, bool is_list, int slow EXECUTE_DATA_DC) { zval *retval; @@ -3005,10 +3005,6 @@ static zend_always_inline void zend_fetch_dimension_address_read(zval *result, z try_array: retval = zend_fetch_dimension_address_inner(Z_ARRVAL_P(container), dim, dim_type, type EXECUTE_DATA_CC); ZVAL_COPY_DEREF(result, retval); - if (cache_slot && !HT_IS_PACKED(Z_ARRVAL_P(container))) { - Bucket *bucket = (Bucket*)((uintptr_t)retval - XtOffsetOf(Bucket, val)); - CACHE_PTR_EX(cache_slot, (void *)(bucket - Z_ARRVAL_P(container)->arData + 1)); - } return; } else if (EXPECTED(Z_TYPE_P(container) == IS_REFERENCE)) { container = Z_REFVAL_P(container); @@ -3149,37 +3145,30 @@ static zend_always_inline void zend_fetch_dimension_address_read(zval *result, z static zend_never_inline void ZEND_FASTCALL zend_fetch_dimension_address_read_R(zval *container, zval *dim, int dim_type OPLINE_DC EXECUTE_DATA_DC) { zval *result = EX_VAR(opline->result.var); - zend_fetch_dimension_address_read(result, container, dim, dim_type, BP_VAR_R, 0, 0, NULL EXECUTE_DATA_CC); -} - -static zend_never_inline void ZEND_FASTCALL zend_fetch_dimension_address_read_R_ex(zval *container, zval *dim, int dim_type, void **cache_slot OPLINE_DC EXECUTE_DATA_DC) -{ - zval *result = EX_VAR(opline->result.var); - ZEND_ASSERT(cache_slot); - zend_fetch_dimension_address_read(result, container, dim, dim_type, BP_VAR_R, 0, 0, cache_slot EXECUTE_DATA_CC); + zend_fetch_dimension_address_read(result, container, dim, dim_type, BP_VAR_R, 0, 0 EXECUTE_DATA_CC); } static zend_never_inline void zend_fetch_dimension_address_read_R_slow(zval *container, zval *dim OPLINE_DC EXECUTE_DATA_DC) { zval *result = EX_VAR(opline->result.var); - zend_fetch_dimension_address_read(result, container, dim, IS_CV, BP_VAR_R, 0, 1, NULL EXECUTE_DATA_CC); + zend_fetch_dimension_address_read(result, container, dim, IS_CV, BP_VAR_R, 0, 1 EXECUTE_DATA_CC); } static zend_never_inline void ZEND_FASTCALL zend_fetch_dimension_address_read_IS(zval *container, zval *dim, int dim_type OPLINE_DC EXECUTE_DATA_DC) { zval *result = EX_VAR(opline->result.var); - zend_fetch_dimension_address_read(result, container, dim, dim_type, BP_VAR_IS, 0, 0, NULL EXECUTE_DATA_CC); + zend_fetch_dimension_address_read(result, container, dim, dim_type, BP_VAR_IS, 0, 0 EXECUTE_DATA_CC); } static zend_never_inline void ZEND_FASTCALL zend_fetch_dimension_address_LIST_r(zval *container, zval *dim, int dim_type OPLINE_DC EXECUTE_DATA_DC) { zval *result = EX_VAR(opline->result.var); - zend_fetch_dimension_address_read(result, container, dim, dim_type, BP_VAR_R, 1, 0, NULL EXECUTE_DATA_CC); + zend_fetch_dimension_address_read(result, container, dim, dim_type, BP_VAR_R, 1, 0 EXECUTE_DATA_CC); } ZEND_API void zend_fetch_dimension_const(zval *result, zval *container, zval *dim, int type) { - zend_fetch_dimension_address_read(result, container, dim, IS_TMP_VAR, type, 0, 0, NULL NO_EXECUTE_DATA_CC); + zend_fetch_dimension_address_read(result, container, dim, IS_TMP_VAR, type, 0, 0 NO_EXECUTE_DATA_CC); } static zend_never_inline zval* ZEND_FASTCALL zend_find_array_dim_slow(HashTable *ht, zval *offset EXECUTE_DATA_DC) diff --git a/Zend/zend_vm_def.h b/Zend/zend_vm_def.h index 966a84709a225..121a9a307adda 100644 --- a/Zend/zend_vm_def.h +++ b/Zend/zend_vm_def.h @@ -10271,6 +10271,8 @@ ZEND_VM_HOT_TYPE_SPEC_HANDLER(ZEND_FETCH_DIM_R, (op->op1_type != IS_CONST && op- zval *container = GET_OP1_ZVAL_PTR_UNDEF(BP_VAR_R); zval *dim = GET_OP2_ZVAL_PTR_UNDEF(BP_VAR_R); + zval *value; + if (EXPECTED(Z_TYPE_P(container) == IS_ARRAY)) { ZEND_VM_C_LABEL(fetch_dim_r_const_index_array): HashTable *ht = Z_ARRVAL_P(container); @@ -10278,8 +10280,9 @@ ZEND_VM_C_LABEL(fetch_dim_r_const_index_array): zend_long offset = Z_LVAL_P(dim); if (HT_IS_PACKED(ht)) { if (EXPECTED((zend_ulong)offset < (zend_ulong)ht->nNumUsed)) { - zval *value = &ht->arPacked[offset]; + value = &ht->arPacked[offset]; if (EXPECTED(Z_TYPE_P(value) != IS_UNDEF)) { +ZEND_VM_C_LABEL(fetch_dim_r_cached_index_found): ZVAL_COPY_DEREF(EX_VAR(opline->result.var), value); if (OP1_TYPE & (IS_TMP_VAR|IS_VAR)) { SAVE_OPLINE(); @@ -10290,36 +10293,42 @@ ZEND_VM_C_LABEL(fetch_dim_r_const_index_array): } } } - SAVE_OPLINE(); - zend_undefined_offset(offset); + ZEND_VM_C_GOTO(fetch_dim_r_cached_index_undef); + } + uintptr_t cached_offset = (uintptr_t)CACHED_PTR(opline->extended_value); + if (cached_offset && ht->nNumUsed >= cached_offset) { + Bucket *b = &ht->arData[cached_offset - 1]; + if (!b->key && b->h == offset) { + value = &b->val; + ZEND_VM_C_GOTO(fetch_dim_r_cached_index_found); + } + } + + value = _zend_hash_index_find(ht, offset); +ZEND_VM_C_LABEL(fetch_dim_r_cached_index_check): + if (EXPECTED(value)) { + Bucket *bucket = (Bucket*)((uintptr_t)value - XtOffsetOf(Bucket, val)); + CACHE_PTR(opline->extended_value, (void *)(bucket - ht->arData + 1)); + ZEND_VM_C_GOTO(fetch_dim_r_cached_index_found); + } else { ZEND_VM_C_GOTO(fetch_dim_r_cached_index_undef); } } else { if (UNEXPECTED(HT_IS_PACKED(ht))) { - SAVE_OPLINE(); - zend_undefined_index(Z_STR_P(dim)); ZEND_VM_C_GOTO(fetch_dim_r_cached_index_undef); } - } - - uintptr_t cached_offset = (uintptr_t)CACHED_PTR(opline->extended_value); - if (cached_offset && ht->nNumUsed >= cached_offset) { - Bucket *b = &ht->arData[cached_offset - 1]; - if (!b->key ? (Z_TYPE_P(dim) == IS_LONG && b->h == Z_LVAL_P(dim)) : (Z_TYPE_P(dim) == IS_STRING && zend_string_equals(b->key, Z_STR_P(dim)))) { - ZVAL_COPY_DEREF(EX_VAR(opline->result.var), &b->val); - if (OP1_TYPE & (IS_TMP_VAR|IS_VAR)) { - FREE_OP1(); - ZEND_VM_NEXT_OPCODE_CHECK_EXCEPTION(); - } else { - ZEND_VM_NEXT_OPCODE(); + uintptr_t cached_offset = (uintptr_t)CACHED_PTR(opline->extended_value); + if (cached_offset && ht->nNumUsed >= cached_offset) { + Bucket *b = &ht->arData[cached_offset - 1]; + if (b->key && zend_string_equals(b->key, Z_STR_P(dim))) { + value = &b->val; + ZEND_VM_C_GOTO(fetch_dim_r_cached_index_found); } } - } - SAVE_OPLINE(); - zend_fetch_dimension_address_read_R_ex(container, dim, OP2_TYPE, CACHE_ADDR(opline->extended_value) OPLINE_CC EXECUTE_DATA_CC); - FREE_OP1(); - ZEND_VM_NEXT_OPCODE_CHECK_EXCEPTION(); + value = zend_hash_find(ht, Z_STR_P(dim)); + ZEND_VM_C_GOTO(fetch_dim_r_cached_index_check); + } } else if (EXPECTED(Z_TYPE_P(container) == IS_REFERENCE)) { container = Z_REFVAL_P(container); if (EXPECTED(Z_TYPE_P(container) == IS_ARRAY)) { @@ -10332,13 +10341,20 @@ ZEND_VM_C_LABEL(fetch_dim_r_const_index_slow): if (OP2_TYPE == IS_CONST && Z_EXTRA_P(dim) == ZEND_EXTRA_VALUE) { dim++; } + SAVE_OPLINE(); zend_fetch_dimension_address_read_R_slow(container, dim OPLINE_CC EXECUTE_DATA_CC); FREE_OP1(); ZEND_VM_NEXT_OPCODE_CHECK_EXCEPTION(); } ZEND_VM_C_LABEL(fetch_dim_r_cached_index_undef): + SAVE_OPLINE(); ZVAL_NULL(EX_VAR(opline->result.var)); + if (Z_TYPE_P(dim) == IS_LONG) { + zend_undefined_offset(Z_LVAL_P(dim)); + } else { + zend_undefined_index(Z_STR_P(dim)); + } FREE_OP1(); ZEND_VM_NEXT_OPCODE_CHECK_EXCEPTION(); } diff --git a/Zend/zend_vm_execute.h b/Zend/zend_vm_execute.h index b59cb356e9242..4e0ad4574b893 100644 --- a/Zend/zend_vm_execute.h +++ b/Zend/zend_vm_execute.h @@ -17122,6 +17122,8 @@ static ZEND_VM_HOT ZEND_OPCODE_HANDLER_RET ZEND_FASTCALL ZEND_FETCH_DIM_R_CACHED zval *container = _get_zval_ptr_var(opline->op1.var EXECUTE_DATA_CC); zval *dim = RT_CONSTANT(opline, opline->op2); + zval *value; + if (EXPECTED(Z_TYPE_P(container) == IS_ARRAY)) { fetch_dim_r_const_index_array: HashTable *ht = Z_ARRVAL_P(container); @@ -17129,8 +17131,9 @@ static ZEND_VM_HOT ZEND_OPCODE_HANDLER_RET ZEND_FASTCALL ZEND_FETCH_DIM_R_CACHED zend_long offset = Z_LVAL_P(dim); if (HT_IS_PACKED(ht)) { if (EXPECTED((zend_ulong)offset < (zend_ulong)ht->nNumUsed)) { - zval *value = &ht->arPacked[offset]; + value = &ht->arPacked[offset]; if (EXPECTED(Z_TYPE_P(value) != IS_UNDEF)) { +fetch_dim_r_cached_index_found: ZVAL_COPY_DEREF(EX_VAR(opline->result.var), value); if ((IS_TMP_VAR|IS_VAR) & (IS_TMP_VAR|IS_VAR)) { SAVE_OPLINE(); @@ -17141,36 +17144,42 @@ static ZEND_VM_HOT ZEND_OPCODE_HANDLER_RET ZEND_FASTCALL ZEND_FETCH_DIM_R_CACHED } } } - SAVE_OPLINE(); - zend_undefined_offset(offset); + goto fetch_dim_r_cached_index_undef; + } + uintptr_t cached_offset = (uintptr_t)CACHED_PTR(opline->extended_value); + if (cached_offset && ht->nNumUsed >= cached_offset) { + Bucket *b = &ht->arData[cached_offset - 1]; + if (!b->key && b->h == offset) { + value = &b->val; + goto fetch_dim_r_cached_index_found; + } + } + + value = _zend_hash_index_find(ht, offset); +fetch_dim_r_cached_index_check: + if (EXPECTED(value)) { + Bucket *bucket = (Bucket*)((uintptr_t)value - XtOffsetOf(Bucket, val)); + CACHE_PTR(opline->extended_value, (void *)(bucket - ht->arData + 1)); + goto fetch_dim_r_cached_index_found; + } else { goto fetch_dim_r_cached_index_undef; } } else { if (UNEXPECTED(HT_IS_PACKED(ht))) { - SAVE_OPLINE(); - zend_undefined_index(Z_STR_P(dim)); goto fetch_dim_r_cached_index_undef; } - } - - uintptr_t cached_offset = (uintptr_t)CACHED_PTR(opline->extended_value); - if (cached_offset && ht->nNumUsed >= cached_offset) { - Bucket *b = &ht->arData[cached_offset - 1]; - if (!b->key ? (Z_TYPE_P(dim) == IS_LONG && b->h == Z_LVAL_P(dim)) : (Z_TYPE_P(dim) == IS_STRING && zend_string_equals(b->key, Z_STR_P(dim)))) { - ZVAL_COPY_DEREF(EX_VAR(opline->result.var), &b->val); - if ((IS_TMP_VAR|IS_VAR) & (IS_TMP_VAR|IS_VAR)) { - zval_ptr_dtor_nogc(EX_VAR(opline->op1.var)); - ZEND_VM_NEXT_OPCODE_CHECK_EXCEPTION(); - } else { - ZEND_VM_NEXT_OPCODE(); + uintptr_t cached_offset = (uintptr_t)CACHED_PTR(opline->extended_value); + if (cached_offset && ht->nNumUsed >= cached_offset) { + Bucket *b = &ht->arData[cached_offset - 1]; + if (b->key && zend_string_equals(b->key, Z_STR_P(dim))) { + value = &b->val; + goto fetch_dim_r_cached_index_found; } } - } - SAVE_OPLINE(); - zend_fetch_dimension_address_read_R_ex(container, dim, IS_CONST, CACHE_ADDR(opline->extended_value) OPLINE_CC EXECUTE_DATA_CC); - zval_ptr_dtor_nogc(EX_VAR(opline->op1.var)); - ZEND_VM_NEXT_OPCODE_CHECK_EXCEPTION(); + value = zend_hash_find(ht, Z_STR_P(dim)); + goto fetch_dim_r_cached_index_check; + } } else if (EXPECTED(Z_TYPE_P(container) == IS_REFERENCE)) { container = Z_REFVAL_P(container); if (EXPECTED(Z_TYPE_P(container) == IS_ARRAY)) { @@ -17183,13 +17192,20 @@ static ZEND_VM_HOT ZEND_OPCODE_HANDLER_RET ZEND_FASTCALL ZEND_FETCH_DIM_R_CACHED if (IS_CONST == IS_CONST && Z_EXTRA_P(dim) == ZEND_EXTRA_VALUE) { dim++; } + SAVE_OPLINE(); zend_fetch_dimension_address_read_R_slow(container, dim OPLINE_CC EXECUTE_DATA_CC); zval_ptr_dtor_nogc(EX_VAR(opline->op1.var)); ZEND_VM_NEXT_OPCODE_CHECK_EXCEPTION(); } fetch_dim_r_cached_index_undef: + SAVE_OPLINE(); ZVAL_NULL(EX_VAR(opline->result.var)); + if (Z_TYPE_P(dim) == IS_LONG) { + zend_undefined_offset(Z_LVAL_P(dim)); + } else { + zend_undefined_index(Z_STR_P(dim)); + } zval_ptr_dtor_nogc(EX_VAR(opline->op1.var)); ZEND_VM_NEXT_OPCODE_CHECK_EXCEPTION(); } @@ -45903,6 +45919,8 @@ static ZEND_VM_HOT ZEND_OPCODE_HANDLER_RET ZEND_FASTCALL ZEND_FETCH_DIM_R_CACHED zval *container = EX_VAR(opline->op1.var); zval *dim = RT_CONSTANT(opline, opline->op2); + zval *value; + if (EXPECTED(Z_TYPE_P(container) == IS_ARRAY)) { fetch_dim_r_const_index_array: HashTable *ht = Z_ARRVAL_P(container); @@ -45910,8 +45928,9 @@ static ZEND_VM_HOT ZEND_OPCODE_HANDLER_RET ZEND_FASTCALL ZEND_FETCH_DIM_R_CACHED zend_long offset = Z_LVAL_P(dim); if (HT_IS_PACKED(ht)) { if (EXPECTED((zend_ulong)offset < (zend_ulong)ht->nNumUsed)) { - zval *value = &ht->arPacked[offset]; + value = &ht->arPacked[offset]; if (EXPECTED(Z_TYPE_P(value) != IS_UNDEF)) { +fetch_dim_r_cached_index_found: ZVAL_COPY_DEREF(EX_VAR(opline->result.var), value); if (IS_CV & (IS_TMP_VAR|IS_VAR)) { SAVE_OPLINE(); @@ -45922,36 +45941,42 @@ static ZEND_VM_HOT ZEND_OPCODE_HANDLER_RET ZEND_FASTCALL ZEND_FETCH_DIM_R_CACHED } } } - SAVE_OPLINE(); - zend_undefined_offset(offset); + goto fetch_dim_r_cached_index_undef; + } + uintptr_t cached_offset = (uintptr_t)CACHED_PTR(opline->extended_value); + if (cached_offset && ht->nNumUsed >= cached_offset) { + Bucket *b = &ht->arData[cached_offset - 1]; + if (!b->key && b->h == offset) { + value = &b->val; + goto fetch_dim_r_cached_index_found; + } + } + + value = _zend_hash_index_find(ht, offset); +fetch_dim_r_cached_index_check: + if (EXPECTED(value)) { + Bucket *bucket = (Bucket*)((uintptr_t)value - XtOffsetOf(Bucket, val)); + CACHE_PTR(opline->extended_value, (void *)(bucket - ht->arData + 1)); + goto fetch_dim_r_cached_index_found; + } else { goto fetch_dim_r_cached_index_undef; } } else { if (UNEXPECTED(HT_IS_PACKED(ht))) { - SAVE_OPLINE(); - zend_undefined_index(Z_STR_P(dim)); goto fetch_dim_r_cached_index_undef; } - } - - uintptr_t cached_offset = (uintptr_t)CACHED_PTR(opline->extended_value); - if (cached_offset && ht->nNumUsed >= cached_offset) { - Bucket *b = &ht->arData[cached_offset - 1]; - if (!b->key ? (Z_TYPE_P(dim) == IS_LONG && b->h == Z_LVAL_P(dim)) : (Z_TYPE_P(dim) == IS_STRING && zend_string_equals(b->key, Z_STR_P(dim)))) { - ZVAL_COPY_DEREF(EX_VAR(opline->result.var), &b->val); - if (IS_CV & (IS_TMP_VAR|IS_VAR)) { - - ZEND_VM_NEXT_OPCODE_CHECK_EXCEPTION(); - } else { - ZEND_VM_NEXT_OPCODE(); + uintptr_t cached_offset = (uintptr_t)CACHED_PTR(opline->extended_value); + if (cached_offset && ht->nNumUsed >= cached_offset) { + Bucket *b = &ht->arData[cached_offset - 1]; + if (b->key && zend_string_equals(b->key, Z_STR_P(dim))) { + value = &b->val; + goto fetch_dim_r_cached_index_found; } } - } - SAVE_OPLINE(); - zend_fetch_dimension_address_read_R_ex(container, dim, IS_CONST, CACHE_ADDR(opline->extended_value) OPLINE_CC EXECUTE_DATA_CC); - - ZEND_VM_NEXT_OPCODE_CHECK_EXCEPTION(); + value = zend_hash_find(ht, Z_STR_P(dim)); + goto fetch_dim_r_cached_index_check; + } } else if (EXPECTED(Z_TYPE_P(container) == IS_REFERENCE)) { container = Z_REFVAL_P(container); if (EXPECTED(Z_TYPE_P(container) == IS_ARRAY)) { @@ -45964,13 +45989,20 @@ static ZEND_VM_HOT ZEND_OPCODE_HANDLER_RET ZEND_FASTCALL ZEND_FETCH_DIM_R_CACHED if (IS_CONST == IS_CONST && Z_EXTRA_P(dim) == ZEND_EXTRA_VALUE) { dim++; } + SAVE_OPLINE(); zend_fetch_dimension_address_read_R_slow(container, dim OPLINE_CC EXECUTE_DATA_CC); ZEND_VM_NEXT_OPCODE_CHECK_EXCEPTION(); } fetch_dim_r_cached_index_undef: + SAVE_OPLINE(); ZVAL_NULL(EX_VAR(opline->result.var)); + if (Z_TYPE_P(dim) == IS_LONG) { + zend_undefined_offset(Z_LVAL_P(dim)); + } else { + zend_undefined_index(Z_STR_P(dim)); + } ZEND_VM_NEXT_OPCODE_CHECK_EXCEPTION(); } From a1ad38eca7015618bb98db496be7c14fb68e8562 Mon Sep 17 00:00:00 2001 From: Ilija Tovilo Date: Mon, 5 May 2025 16:34:32 +0200 Subject: [PATCH 6/6] Fix decl after goto label error --- Zend/zend_vm_def.h | 2 +- Zend/zend_vm_execute.h | 4 ++-- 2 files changed, 3 insertions(+), 3 deletions(-) diff --git a/Zend/zend_vm_def.h b/Zend/zend_vm_def.h index 121a9a307adda..0d2faceaf9ddc 100644 --- a/Zend/zend_vm_def.h +++ b/Zend/zend_vm_def.h @@ -10274,7 +10274,7 @@ ZEND_VM_HOT_TYPE_SPEC_HANDLER(ZEND_FETCH_DIM_R, (op->op1_type != IS_CONST && op- zval *value; if (EXPECTED(Z_TYPE_P(container) == IS_ARRAY)) { -ZEND_VM_C_LABEL(fetch_dim_r_const_index_array): +ZEND_VM_C_LABEL(fetch_dim_r_const_index_array):; HashTable *ht = Z_ARRVAL_P(container); if (Z_TYPE_P(dim) == IS_LONG) { zend_long offset = Z_LVAL_P(dim); diff --git a/Zend/zend_vm_execute.h b/Zend/zend_vm_execute.h index 4e0ad4574b893..e8ff178717b16 100644 --- a/Zend/zend_vm_execute.h +++ b/Zend/zend_vm_execute.h @@ -17125,7 +17125,7 @@ static ZEND_VM_HOT ZEND_OPCODE_HANDLER_RET ZEND_FASTCALL ZEND_FETCH_DIM_R_CACHED zval *value; if (EXPECTED(Z_TYPE_P(container) == IS_ARRAY)) { -fetch_dim_r_const_index_array: +fetch_dim_r_const_index_array:; HashTable *ht = Z_ARRVAL_P(container); if (Z_TYPE_P(dim) == IS_LONG) { zend_long offset = Z_LVAL_P(dim); @@ -45922,7 +45922,7 @@ static ZEND_VM_HOT ZEND_OPCODE_HANDLER_RET ZEND_FASTCALL ZEND_FETCH_DIM_R_CACHED zval *value; if (EXPECTED(Z_TYPE_P(container) == IS_ARRAY)) { -fetch_dim_r_const_index_array: +fetch_dim_r_const_index_array:; HashTable *ht = Z_ARRVAL_P(container); if (Z_TYPE_P(dim) == IS_LONG) { zend_long offset = Z_LVAL_P(dim);