From: Dmitry Stogov Date: Fri, 15 Feb 2019 14:52:59 +0000 (+0300) Subject: Merge branch 'PHP-7.4' X-Git-Url: https://granicus.if.org/sourcecode?a=commitdiff_plain;h=1b281f801e954cab1c0a79b3b1d60f06ffee20b6;p=php Merge branch 'PHP-7.4' * PHP-7.4: Avoid useless code duplication, because of unused specialization --- 1b281f801e954cab1c0a79b3b1d60f06ffee20b6 diff --cc Zend/zend_vm_execute.h index ab6ada935d,72b98dc1bd..576872d18b --- a/Zend/zend_vm_execute.h +++ b/Zend/zend_vm_execute.h @@@ -44006,32 -41507,24 +42281,33 @@@ static ZEND_OPCODE_HANDLER_RET ZEND_FAS } } - post_incdec_object: + pre_incdec_object: /* here we are sure we are dealing with an object */ + zobj = Z_OBJ_P(object); + if (IS_CONST == IS_CONST) { + name = Z_STR_P(property); + } else { + name = zval_get_tmp_string(property, &tmp_name); + } cache_slot = (IS_CONST == IS_CONST) ? CACHE_ADDR(opline->extended_value) : NULL; - if (EXPECTED((zptr = Z_OBJ_HT_P(object)->get_property_ptr_ptr(object, property, BP_VAR_RW, cache_slot)) != NULL)) { + if (EXPECTED((zptr = zobj->handlers->get_property_ptr_ptr(zobj, name, BP_VAR_RW, cache_slot)) != NULL)) { if (UNEXPECTED(Z_ISERROR_P(zptr))) { - ZVAL_NULL(EX_VAR(opline->result.var)); + if (UNEXPECTED(RETURN_VALUE_USED(opline))) { + ZVAL_NULL(EX_VAR(opline->result.var)); + } } else { if (IS_CONST == IS_CONST) { - prop_info = (zend_property_info*)CACHED_PTR_EX(cache_slot + 2); + prop_info = (zend_property_info *) CACHED_PTR_EX(cache_slot + 2); } else { prop_info = zend_object_fetch_property_type_info(Z_OBJ_P(object), zptr); } - - zend_post_incdec_property_zval(zptr, prop_info, inc OPLINE_CC EXECUTE_DATA_CC); + zend_pre_incdec_property_zval(zptr, prop_info, inc OPLINE_CC EXECUTE_DATA_CC); } } else { - zend_post_incdec_overloaded_property(zobj, name, cache_slot, inc OPLINE_CC EXECUTE_DATA_CC); - zend_pre_incdec_overloaded_property(object, property, cache_slot, inc OPLINE_CC EXECUTE_DATA_CC); ++ zend_pre_incdec_overloaded_property(zobj, name, cache_slot, inc OPLINE_CC EXECUTE_DATA_CC); + } + if (IS_CONST != IS_CONST) { + zend_tmp_string_release(tmp_name); } } while (0); @@@ -44039,30 -41532,67 +42315,78 @@@ ZEND_VM_NEXT_OPCODE_CHECK_EXCEPTION(); } - static ZEND_OPCODE_HANDLER_RET ZEND_FASTCALL ZEND_POST_INC_OBJ_SPEC_CV_CONST_HANDLER(ZEND_OPCODE_HANDLER_ARGS) + static ZEND_OPCODE_HANDLER_RET ZEND_FASTCALL ZEND_PRE_INC_OBJ_SPEC_CV_CONST_HANDLER(ZEND_OPCODE_HANDLER_ARGS) { - ZEND_VM_TAIL_CALL(zend_post_incdec_property_helper_SPEC_CV_CONST(1 ZEND_OPCODE_HANDLER_ARGS_PASSTHRU_CC)); + ZEND_VM_TAIL_CALL(zend_pre_incdec_property_helper_SPEC_CV_CONST(1 ZEND_OPCODE_HANDLER_ARGS_PASSTHRU_CC)); } - static ZEND_OPCODE_HANDLER_RET ZEND_FASTCALL ZEND_POST_DEC_OBJ_SPEC_CV_CONST_HANDLER(ZEND_OPCODE_HANDLER_ARGS) + static ZEND_OPCODE_HANDLER_RET ZEND_FASTCALL ZEND_PRE_DEC_OBJ_SPEC_CV_CONST_HANDLER(ZEND_OPCODE_HANDLER_ARGS) { - ZEND_VM_TAIL_CALL(zend_post_incdec_property_helper_SPEC_CV_CONST(0 ZEND_OPCODE_HANDLER_ARGS_PASSTHRU_CC)); + ZEND_VM_TAIL_CALL(zend_pre_incdec_property_helper_SPEC_CV_CONST(0 ZEND_OPCODE_HANDLER_ARGS_PASSTHRU_CC)); } - static ZEND_OPCODE_HANDLER_RET ZEND_FASTCALL zend_pre_incdec_static_property_helper_SPEC_CV_CONST(int inc ZEND_OPCODE_HANDLER_ARGS_DC) + static ZEND_OPCODE_HANDLER_RET ZEND_FASTCALL zend_post_incdec_property_helper_SPEC_CV_CONST(int inc ZEND_OPCODE_HANDLER_ARGS_DC) { USE_OPLINE - zval *prop; + + zval *object; + zval *property; + zval *zptr; + void **cache_slot; zend_property_info *prop_info; ++ zend_object *zobj; ++ zend_string *name, *tmp_name; SAVE_OPLINE(); + object = _get_zval_ptr_cv_BP_VAR_RW(opline->op1.var EXECUTE_DATA_CC); - if (zend_fetch_static_property_address(&prop, &prop_info, opline->extended_value, BP_VAR_RW, 0 OPLINE_CC EXECUTE_DATA_CC) != SUCCESS) { - UNDEF_RESULT(); - HANDLE_EXCEPTION(); + if (IS_CV == IS_UNUSED && UNEXPECTED(Z_TYPE_P(object) == IS_UNDEF)) { + ZEND_VM_TAIL_CALL(zend_this_not_in_object_context_helper_SPEC(ZEND_OPCODE_HANDLER_ARGS_PASSTHRU)); } - zend_pre_incdec_property_zval(prop, prop_info->type ? prop_info : NULL, inc OPLINE_CC EXECUTE_DATA_CC); + property = RT_CONSTANT(opline, opline->op2); + + do { + if (IS_CV != IS_UNUSED && UNEXPECTED(Z_TYPE_P(object) != IS_OBJECT)) { + if (Z_ISREF_P(object) && Z_TYPE_P(Z_REFVAL_P(object)) == IS_OBJECT) { + object = Z_REFVAL_P(object); + goto post_incdec_object; + } + object = make_real_object(object, property OPLINE_CC EXECUTE_DATA_CC); + if (UNEXPECTED(!object)) { + break; + } + } + + post_incdec_object: + /* here we are sure we are dealing with an object */ ++ zobj = Z_OBJ_P(object); ++ if (IS_CONST == IS_CONST) { ++ name = Z_STR_P(property); ++ } else { ++ name = zval_get_tmp_string(property, &tmp_name); ++ } + cache_slot = (IS_CONST == IS_CONST) ? CACHE_ADDR(opline->extended_value) : NULL; - if (EXPECTED((zptr = Z_OBJ_HT_P(object)->get_property_ptr_ptr(object, property, BP_VAR_RW, cache_slot)) != NULL)) { ++ if (EXPECTED((zptr = zobj->handlers->get_property_ptr_ptr(zobj, name, BP_VAR_RW, cache_slot)) != NULL)) { + if (UNEXPECTED(Z_ISERROR_P(zptr))) { + ZVAL_NULL(EX_VAR(opline->result.var)); + } else { + if (IS_CONST == IS_CONST) { + prop_info = (zend_property_info*)CACHED_PTR_EX(cache_slot + 2); + } else { + prop_info = zend_object_fetch_property_type_info(Z_OBJ_P(object), zptr); + } + + zend_post_incdec_property_zval(zptr, prop_info, inc OPLINE_CC EXECUTE_DATA_CC); + } + } else { - zend_post_incdec_overloaded_property(object, property, cache_slot, inc OPLINE_CC EXECUTE_DATA_CC); ++ zend_post_incdec_overloaded_property(zobj, name, cache_slot, inc OPLINE_CC EXECUTE_DATA_CC); ++ } ++ if (IS_CONST != IS_CONST) { ++ zend_tmp_string_release(tmp_name); + } + } while (0); + ZEND_VM_NEXT_OPCODE_CHECK_EXCEPTION(); } @@@ -45154,127 -42459,132 +43309,145 @@@ static ZEND_OPCODE_HANDLER_RET ZEND_FAS { USE_OPLINE - zval *prop, *value; - zend_property_info *prop_info; + zval *object, *property, *value, tmp; ++ zend_object *zobj; ++ zend_string *name, *tmp_name; SAVE_OPLINE(); + object = EX_VAR(opline->op1.var); - if (zend_fetch_static_property_address(&prop, &prop_info, opline->extended_value, BP_VAR_W, 0 OPLINE_CC EXECUTE_DATA_CC) != SUCCESS) { - - UNDEF_RESULT(); - HANDLE_EXCEPTION(); - } - - value = RT_CONSTANT((opline+1), (opline+1)->op1); - - if (UNEXPECTED(prop_info->type)) { - value = zend_assign_to_typed_prop(prop_info, prop, value EXECUTE_DATA_CC); - - } else { - value = zend_assign_to_variable(prop, value, IS_CONST, EX_USES_STRICT_TYPES()); - } - - if (UNEXPECTED(RETURN_VALUE_USED(opline))) { - ZVAL_COPY(EX_VAR(opline->result.var), value); + if (IS_CV == IS_UNUSED && UNEXPECTED(Z_TYPE_P(object) == IS_UNDEF)) { + ZEND_VM_TAIL_CALL(zend_this_not_in_object_context_helper_SPEC(ZEND_OPCODE_HANDLER_ARGS_PASSTHRU)); } - /* assign_static_prop has two opcodes! */ - ZEND_VM_NEXT_OPCODE_EX(1, 2); - } - - static ZEND_OPCODE_HANDLER_RET ZEND_FASTCALL ZEND_ASSIGN_STATIC_PROP_SPEC_CV_CONST_OP_DATA_TMP_HANDLER(ZEND_OPCODE_HANDLER_ARGS) - { - USE_OPLINE - zend_free_op free_op_data; - zval *prop, *value; - zend_property_info *prop_info; + property = RT_CONSTANT(opline, opline->op2); + value = _get_zval_ptr_cv_BP_VAR_R((opline+1)->op1.var EXECUTE_DATA_CC); - SAVE_OPLINE(); + if (IS_CV != IS_UNUSED && UNEXPECTED(Z_TYPE_P(object) != IS_OBJECT)) { + if (Z_ISREF_P(object) && Z_TYPE_P(Z_REFVAL_P(object)) == IS_OBJECT) { + object = Z_REFVAL_P(object); + goto assign_object; + } + object = make_real_object(object, property OPLINE_CC EXECUTE_DATA_CC); + if (UNEXPECTED(!object)) { - if (zend_fetch_static_property_address(&prop, &prop_info, opline->extended_value, BP_VAR_W, 0 OPLINE_CC EXECUTE_DATA_CC) != SUCCESS) { - zval_ptr_dtor_nogc(EX_VAR((opline+1)->op1.var)); - UNDEF_RESULT(); - HANDLE_EXCEPTION(); + goto exit_assign_obj; + } } - value = _get_zval_ptr_tmp((opline+1)->op1.var, &free_op_data EXECUTE_DATA_CC); + assign_object: ++ zobj = Z_OBJ_P(object); + if (IS_CONST == IS_CONST && - EXPECTED(Z_OBJCE_P(object) == CACHED_PTR(opline->extended_value))) { ++ EXPECTED(zobj->ce == CACHED_PTR(opline->extended_value))) { + void **cache_slot = CACHE_ADDR(opline->extended_value); + uintptr_t prop_offset = (uintptr_t)CACHED_PTR_EX(cache_slot + 1); + zend_object *zobj = Z_OBJ_P(object); + zval *property_val; - if (UNEXPECTED(prop_info->type)) { - value = zend_assign_to_typed_prop(prop_info, prop, value EXECUTE_DATA_CC); - zval_ptr_dtor_nogc(free_op_data); - } else { - value = zend_assign_to_variable(prop, value, IS_TMP_VAR, EX_USES_STRICT_TYPES()); - } + if (EXPECTED(IS_VALID_PROPERTY_OFFSET(prop_offset))) { + property_val = OBJ_PROP(zobj, prop_offset); + if (Z_TYPE_P(property_val) != IS_UNDEF) { + zend_property_info *prop_info = (zend_property_info*) CACHED_PTR_EX(cache_slot + 2); - if (UNEXPECTED(RETURN_VALUE_USED(opline))) { - ZVAL_COPY(EX_VAR(opline->result.var), value); - } + if (UNEXPECTED(prop_info != NULL)) { + zend_uchar orig_type = IS_UNDEF; - /* assign_static_prop has two opcodes! */ - ZEND_VM_NEXT_OPCODE_EX(1, 2); - } + if (IS_CV == IS_CONST) { + orig_type = Z_TYPE_P(value); + } - static ZEND_OPCODE_HANDLER_RET ZEND_FASTCALL ZEND_ASSIGN_STATIC_PROP_SPEC_CV_CONST_OP_DATA_VAR_HANDLER(ZEND_OPCODE_HANDLER_ARGS) - { - USE_OPLINE - zend_free_op free_op_data; - zval *prop, *value; - zend_property_info *prop_info; + value = zend_assign_to_typed_prop(prop_info, property_val, value EXECUTE_DATA_CC); - SAVE_OPLINE(); + /* will remain valid, thus no need to check prop_info in future here */ + if (IS_CV == IS_CONST && Z_TYPE_P(value) == orig_type) { + CACHE_PTR_EX(cache_slot + 2, NULL); + } - if (zend_fetch_static_property_address(&prop, &prop_info, opline->extended_value, BP_VAR_W, 0 OPLINE_CC EXECUTE_DATA_CC) != SUCCESS) { - zval_ptr_dtor_nogc(EX_VAR((opline+1)->op1.var)); - UNDEF_RESULT(); - HANDLE_EXCEPTION(); - } + } else { + fast_assign_obj: + value = zend_assign_to_variable(property_val, value, IS_CV, EX_USES_STRICT_TYPES()); + } + if (UNEXPECTED(RETURN_VALUE_USED(opline))) { + ZVAL_COPY(EX_VAR(opline->result.var), value); + } + goto exit_assign_obj; + } + } else { + if (EXPECTED(zobj->properties != NULL)) { + if (UNEXPECTED(GC_REFCOUNT(zobj->properties) > 1)) { + if (EXPECTED(!(GC_FLAGS(zobj->properties) & IS_ARRAY_IMMUTABLE))) { + GC_DELREF(zobj->properties); + } + zobj->properties = zend_array_dup(zobj->properties); + } + property_val = zend_hash_find_ex(zobj->properties, Z_STR_P(property), 1); + if (property_val) { + goto fast_assign_obj; + } + } - value = _get_zval_ptr_var((opline+1)->op1.var, &free_op_data EXECUTE_DATA_CC); + if (!zobj->ce->__set) { - if (UNEXPECTED(prop_info->type)) { - value = zend_assign_to_typed_prop(prop_info, prop, value EXECUTE_DATA_CC); - zval_ptr_dtor_nogc(free_op_data); - } else { - value = zend_assign_to_variable(prop, value, IS_VAR, EX_USES_STRICT_TYPES()); + if (EXPECTED(zobj->properties == NULL)) { + rebuild_object_properties(zobj); + } + if (IS_CV == IS_CONST) { + if (UNEXPECTED(Z_OPT_REFCOUNTED_P(value))) { + Z_ADDREF_P(value); + } + } else if (IS_CV != IS_TMP_VAR) { + if (Z_ISREF_P(value)) { + if (IS_CV == IS_VAR) { + zend_reference *ref = Z_REF_P(value); + if (GC_DELREF(ref) == 0) { + ZVAL_COPY_VALUE(&tmp, Z_REFVAL_P(value)); + efree_size(ref, sizeof(zend_reference)); + value = &tmp; + } else { + value = Z_REFVAL_P(value); + Z_TRY_ADDREF_P(value); + } + } else { + value = Z_REFVAL_P(value); + Z_TRY_ADDREF_P(value); + } + } else if (IS_CV == IS_CV) { + Z_TRY_ADDREF_P(value); + } + } + zend_hash_add_new(zobj->properties, Z_STR_P(property), value); + if (UNEXPECTED(RETURN_VALUE_USED(opline))) { + ZVAL_COPY(EX_VAR(opline->result.var), value); + } + goto exit_assign_obj; + } + } } - if (UNEXPECTED(RETURN_VALUE_USED(opline))) { - ZVAL_COPY(EX_VAR(opline->result.var), value); + if (IS_CV == IS_CV || IS_CV == IS_VAR) { + ZVAL_DEREF(value); } - /* assign_static_prop has two opcodes! */ - ZEND_VM_NEXT_OPCODE_EX(1, 2); - } - - static ZEND_OPCODE_HANDLER_RET ZEND_FASTCALL ZEND_ASSIGN_STATIC_PROP_SPEC_CV_CONST_OP_DATA_CV_HANDLER(ZEND_OPCODE_HANDLER_ARGS) - { - USE_OPLINE - - zval *prop, *value; - zend_property_info *prop_info; - - SAVE_OPLINE(); - - if (zend_fetch_static_property_address(&prop, &prop_info, opline->extended_value, BP_VAR_W, 0 OPLINE_CC EXECUTE_DATA_CC) != SUCCESS) { - - UNDEF_RESULT(); - HANDLE_EXCEPTION(); - property = Z_OBJ_HT_P(object)->write_property(object, property, value, (IS_CONST == IS_CONST) ? CACHE_ADDR(opline->extended_value) : NULL); ++ if (IS_CONST == IS_CONST) { ++ name = Z_STR_P(property); ++ } else { ++ name = zval_get_tmp_string(property, &tmp_name); + } + - value = _get_zval_ptr_cv_BP_VAR_R((opline+1)->op1.var EXECUTE_DATA_CC); - - if (UNEXPECTED(prop_info->type)) { - value = zend_assign_to_typed_prop(prop_info, prop, value EXECUTE_DATA_CC); ++ property = zobj->handlers->write_property(zobj, name, value, (IS_CONST == IS_CONST) ? CACHE_ADDR(opline->extended_value) : NULL); + - } else { - value = zend_assign_to_variable(prop, value, IS_CV, EX_USES_STRICT_TYPES()); ++ if (IS_CONST != IS_CONST) { ++ zend_tmp_string_release(tmp_name); + } if (UNEXPECTED(RETURN_VALUE_USED(opline))) { - ZVAL_COPY(EX_VAR(opline->result.var), value); + ZVAL_COPY(EX_VAR(opline->result.var), property); } - /* assign_static_prop has two opcodes! */ + exit_assign_obj: + + + /* assign_obj has two opcodes! */ ZEND_VM_NEXT_OPCODE_EX(1, 2); }