From: Dmitry Stogov Date: Thu, 25 May 2017 09:52:34 +0000 (+0300) Subject: Added ZEND_COUNT instruction, to implement corresponding builtin. X-Git-Tag: php-7.2.0alpha1~57^2~29 X-Git-Url: https://granicus.if.org/sourcecode?a=commitdiff_plain;h=cd953269d3d486f775f1935731b1d6d44f12a350;p=php Added ZEND_COUNT instruction, to implement corresponding builtin. --- diff --git a/NEWS b/NEWS index e0a9e92d8e..1e3803a6e6 100644 --- a/NEWS +++ b/NEWS @@ -3,6 +3,7 @@ PHP NEWS ?? ??? ????, PHP 7.2 - Core: + . Added ZEND_COUNT instruction, to implement corresponding builtin. (Dmitry) . "Countable" interface is moved from SPL to Core. (Dmitry) . Added ZEND_IN_ARRAY instruction, implementing optimized in_array() builtin function, through hash lookup in flipped array. (Dmitry) diff --git a/Zend/zend_compile.c b/Zend/zend_compile.c index 0a368a4a4b..2858e6a906 100644 --- a/Zend/zend_compile.c +++ b/Zend/zend_compile.c @@ -3723,6 +3723,20 @@ static int zend_compile_func_in_array(znode *result, zend_ast_list *args) /* {{{ } /* }}} */ +int zend_compile_func_count(znode *result, zend_ast_list *args) /* {{{ */ +{ + znode arg_node; + + if (args->children != 1 || args->child[0]->kind == ZEND_AST_UNPACK) { + return FAILURE; + } + + zend_compile_expr(&arg_node, args->child[0]); + zend_emit_op_tmp(result, ZEND_COUNT, &arg_node, NULL); + return SUCCESS; +} +/* }}} */ + int zend_try_compile_special_func(znode *result, zend_string *lcname, zend_ast_list *args, zend_function *fbc, uint32_t type) /* {{{ */ { if (fbc->internal_function.handler == ZEND_FN(display_disabled_function)) { @@ -3783,6 +3797,8 @@ int zend_try_compile_special_func(znode *result, zend_string *lcname, zend_ast_l return zend_compile_func_cuf(result, args, lcname); } else if (zend_string_equals_literal(lcname, "in_array")) { return zend_compile_func_in_array(result, args); + } else if (zend_string_equals_literal(lcname, "count")) { + return zend_compile_func_count(result, args); } else { return FAILURE; } diff --git a/Zend/zend_vm_def.h b/Zend/zend_vm_def.h index b1888cc857..621e5a75d0 100644 --- a/Zend/zend_vm_def.h +++ b/Zend/zend_vm_def.h @@ -8142,6 +8142,52 @@ ZEND_VM_HANDLER(189, ZEND_IN_ARRAY, CONST|TMP|VAR|CV, CONST, NUM) ZEND_VM_NEXT_OPCODE_CHECK_EXCEPTION(); } +ZEND_VM_HANDLER(190, ZEND_COUNT, CONST|TMP|VAR|CV, UNUSED) +{ + USE_OPLINE + zend_free_op free_op1; + zval *op1; + zend_long count; + + SAVE_OPLINE(); + op1 = GET_OP1_ZVAL_PTR_DEREF(BP_VAR_R); + do { + if (Z_TYPE_P(op1) == IS_ARRAY) { + count = zend_array_count(Z_ARRVAL_P(op1)); + break; + } else if (Z_TYPE_P(op1) == IS_OBJECT) { + /* first, we check if the handler is defined */ + if (Z_OBJ_HT_P(op1)->count_elements) { + if (SUCCESS == Z_OBJ_HT_P(op1)->count_elements(op1, &count)) { + break; + } + } + + /* if not and the object implements Countable we call its count() method */ + if (instanceof_function(Z_OBJCE_P(op1), zend_ce_countable)) { + zval retval; + + zend_call_method_with_0_params(op1, NULL, NULL, "count", &retval); + count = zval_get_long(&retval); + zval_ptr_dtor(&retval); + break; + } + + /* If There's no handler and it doesn't implement Countable then add a warning */ + count = 1; + } else if (Z_TYPE_P(op1) == IS_NULL) { + count = 0; + } else { + count = 1; + } + zend_error(E_WARNING, "count(): Parameter must be an array or an object that implements Countable"); + } while (0); + + ZVAL_LONG(EX_VAR(opline->result.var), count); + FREE_OP1(); + ZEND_VM_NEXT_OPCODE_CHECK_EXCEPTION(); +} + ZEND_VM_HOT_TYPE_SPEC_HANDLER(ZEND_ADD, (res_info == MAY_BE_LONG && op1_info == MAY_BE_LONG && op2_info == MAY_BE_LONG), ZEND_ADD_LONG_NO_OVERFLOW, CONST|TMPVARCV, CONST|TMPVARCV, SPEC(NO_CONST_CONST,COMMUTATIVE)) { USE_OPLINE diff --git a/Zend/zend_vm_execute.h b/Zend/zend_vm_execute.h index 4be3872bce..b2c701c47b 100644 --- a/Zend/zend_vm_execute.h +++ b/Zend/zend_vm_execute.h @@ -8069,6 +8069,52 @@ static ZEND_OPCODE_HANDLER_RET ZEND_FASTCALL ZEND_YIELD_SPEC_CONST_UNUSED_HANDLE ZEND_VM_RETURN(); } +static ZEND_OPCODE_HANDLER_RET ZEND_FASTCALL ZEND_COUNT_SPEC_CONST_UNUSED_HANDLER(ZEND_OPCODE_HANDLER_ARGS) +{ + USE_OPLINE + + zval *op1; + zend_long count; + + SAVE_OPLINE(); + op1 = EX_CONSTANT(opline->op1); + do { + if (Z_TYPE_P(op1) == IS_ARRAY) { + count = zend_array_count(Z_ARRVAL_P(op1)); + break; + } else if (Z_TYPE_P(op1) == IS_OBJECT) { + /* first, we check if the handler is defined */ + if (Z_OBJ_HT_P(op1)->count_elements) { + if (SUCCESS == Z_OBJ_HT_P(op1)->count_elements(op1, &count)) { + break; + } + } + + /* if not and the object implements Countable we call its count() method */ + if (instanceof_function(Z_OBJCE_P(op1), zend_ce_countable)) { + zval retval; + + zend_call_method_with_0_params(op1, NULL, NULL, "count", &retval); + count = zval_get_long(&retval); + zval_ptr_dtor(&retval); + break; + } + + /* If There's no handler and it doesn't implement Countable then add a warning */ + count = 1; + } else if (Z_TYPE_P(op1) == IS_NULL) { + count = 0; + } else { + count = 1; + } + zend_error(E_WARNING, "count(): Parameter must be an array or an object that implements Countable"); + } while (0); + + ZVAL_LONG(EX_VAR(opline->result.var), count); + + ZEND_VM_NEXT_OPCODE_CHECK_EXCEPTION(); +} + static ZEND_OPCODE_HANDLER_RET ZEND_FASTCALL ZEND_ADD_SPEC_CONST_CV_HANDLER(ZEND_OPCODE_HANDLER_ARGS) { USE_OPLINE @@ -14537,6 +14583,52 @@ static ZEND_OPCODE_HANDLER_RET ZEND_FASTCALL ZEND_YIELD_SPEC_TMP_UNUSED_HANDLER( ZEND_VM_RETURN(); } +static ZEND_OPCODE_HANDLER_RET ZEND_FASTCALL ZEND_COUNT_SPEC_TMP_UNUSED_HANDLER(ZEND_OPCODE_HANDLER_ARGS) +{ + USE_OPLINE + zend_free_op free_op1; + zval *op1; + zend_long count; + + SAVE_OPLINE(); + op1 = _get_zval_ptr_tmp(opline->op1.var, execute_data, &free_op1); + do { + if (Z_TYPE_P(op1) == IS_ARRAY) { + count = zend_array_count(Z_ARRVAL_P(op1)); + break; + } else if (Z_TYPE_P(op1) == IS_OBJECT) { + /* first, we check if the handler is defined */ + if (Z_OBJ_HT_P(op1)->count_elements) { + if (SUCCESS == Z_OBJ_HT_P(op1)->count_elements(op1, &count)) { + break; + } + } + + /* if not and the object implements Countable we call its count() method */ + if (instanceof_function(Z_OBJCE_P(op1), zend_ce_countable)) { + zval retval; + + zend_call_method_with_0_params(op1, NULL, NULL, "count", &retval); + count = zval_get_long(&retval); + zval_ptr_dtor(&retval); + break; + } + + /* If There's no handler and it doesn't implement Countable then add a warning */ + count = 1; + } else if (Z_TYPE_P(op1) == IS_NULL) { + count = 0; + } else { + count = 1; + } + zend_error(E_WARNING, "count(): Parameter must be an array or an object that implements Countable"); + } while (0); + + ZVAL_LONG(EX_VAR(opline->result.var), count); + zval_ptr_dtor_nogc(free_op1); + ZEND_VM_NEXT_OPCODE_CHECK_EXCEPTION(); +} + static ZEND_OPCODE_HANDLER_RET ZEND_FASTCALL ZEND_IS_IDENTICAL_SPEC_TMP_CV_HANDLER(ZEND_OPCODE_HANDLER_ARGS) { USE_OPLINE @@ -21613,6 +21705,52 @@ static ZEND_OPCODE_HANDLER_RET ZEND_FASTCALL ZEND_MAKE_REF_SPEC_VAR_UNUSED_HANDL ZEND_VM_NEXT_OPCODE(); } +static ZEND_OPCODE_HANDLER_RET ZEND_FASTCALL ZEND_COUNT_SPEC_VAR_UNUSED_HANDLER(ZEND_OPCODE_HANDLER_ARGS) +{ + USE_OPLINE + zend_free_op free_op1; + zval *op1; + zend_long count; + + SAVE_OPLINE(); + op1 = _get_zval_ptr_var_deref(opline->op1.var, execute_data, &free_op1); + do { + if (Z_TYPE_P(op1) == IS_ARRAY) { + count = zend_array_count(Z_ARRVAL_P(op1)); + break; + } else if (Z_TYPE_P(op1) == IS_OBJECT) { + /* first, we check if the handler is defined */ + if (Z_OBJ_HT_P(op1)->count_elements) { + if (SUCCESS == Z_OBJ_HT_P(op1)->count_elements(op1, &count)) { + break; + } + } + + /* if not and the object implements Countable we call its count() method */ + if (instanceof_function(Z_OBJCE_P(op1), zend_ce_countable)) { + zval retval; + + zend_call_method_with_0_params(op1, NULL, NULL, "count", &retval); + count = zval_get_long(&retval); + zval_ptr_dtor(&retval); + break; + } + + /* If There's no handler and it doesn't implement Countable then add a warning */ + count = 1; + } else if (Z_TYPE_P(op1) == IS_NULL) { + count = 0; + } else { + count = 1; + } + zend_error(E_WARNING, "count(): Parameter must be an array or an object that implements Countable"); + } while (0); + + ZVAL_LONG(EX_VAR(opline->result.var), count); + zval_ptr_dtor_nogc(free_op1); + ZEND_VM_NEXT_OPCODE_CHECK_EXCEPTION(); +} + static ZEND_OPCODE_HANDLER_RET ZEND_FASTCALL ZEND_IS_IDENTICAL_SPEC_VAR_CV_HANDLER(ZEND_OPCODE_HANDLER_ARGS) { USE_OPLINE @@ -40669,6 +40807,52 @@ static ZEND_OPCODE_HANDLER_RET ZEND_FASTCALL ZEND_MAKE_REF_SPEC_CV_UNUSED_HANDLE ZEND_VM_NEXT_OPCODE(); } +static ZEND_OPCODE_HANDLER_RET ZEND_FASTCALL ZEND_COUNT_SPEC_CV_UNUSED_HANDLER(ZEND_OPCODE_HANDLER_ARGS) +{ + USE_OPLINE + + zval *op1; + zend_long count; + + SAVE_OPLINE(); + op1 = _get_zval_ptr_cv_deref_BP_VAR_R(execute_data, opline->op1.var); + do { + if (Z_TYPE_P(op1) == IS_ARRAY) { + count = zend_array_count(Z_ARRVAL_P(op1)); + break; + } else if (Z_TYPE_P(op1) == IS_OBJECT) { + /* first, we check if the handler is defined */ + if (Z_OBJ_HT_P(op1)->count_elements) { + if (SUCCESS == Z_OBJ_HT_P(op1)->count_elements(op1, &count)) { + break; + } + } + + /* if not and the object implements Countable we call its count() method */ + if (instanceof_function(Z_OBJCE_P(op1), zend_ce_countable)) { + zval retval; + + zend_call_method_with_0_params(op1, NULL, NULL, "count", &retval); + count = zval_get_long(&retval); + zval_ptr_dtor(&retval); + break; + } + + /* If There's no handler and it doesn't implement Countable then add a warning */ + count = 1; + } else if (Z_TYPE_P(op1) == IS_NULL) { + count = 0; + } else { + count = 1; + } + zend_error(E_WARNING, "count(): Parameter must be an array or an object that implements Countable"); + } while (0); + + ZVAL_LONG(EX_VAR(opline->result.var), count); + + ZEND_VM_NEXT_OPCODE_CHECK_EXCEPTION(); +} + static ZEND_OPCODE_HANDLER_RET ZEND_FASTCALL ZEND_ADD_SPEC_CV_CV_HANDLER(ZEND_OPCODE_HANDLER_ARGS) { USE_OPLINE @@ -57956,6 +58140,31 @@ ZEND_API void execute_ex(zend_execute_data *ex) (void*)&&ZEND_NULL_LABEL, (void*)&&ZEND_NULL_LABEL, (void*)&&ZEND_NULL_LABEL, + (void*)&&ZEND_NULL_LABEL, + (void*)&&ZEND_NULL_LABEL, + (void*)&&ZEND_COUNT_SPEC_CONST_UNUSED_LABEL, + (void*)&&ZEND_NULL_LABEL, + (void*)&&ZEND_NULL_LABEL, + (void*)&&ZEND_NULL_LABEL, + (void*)&&ZEND_NULL_LABEL, + (void*)&&ZEND_COUNT_SPEC_TMP_UNUSED_LABEL, + (void*)&&ZEND_NULL_LABEL, + (void*)&&ZEND_NULL_LABEL, + (void*)&&ZEND_NULL_LABEL, + (void*)&&ZEND_NULL_LABEL, + (void*)&&ZEND_COUNT_SPEC_VAR_UNUSED_LABEL, + (void*)&&ZEND_NULL_LABEL, + (void*)&&ZEND_NULL_LABEL, + (void*)&&ZEND_NULL_LABEL, + (void*)&&ZEND_NULL_LABEL, + (void*)&&ZEND_NULL_LABEL, + (void*)&&ZEND_NULL_LABEL, + (void*)&&ZEND_NULL_LABEL, + (void*)&&ZEND_NULL_LABEL, + (void*)&&ZEND_NULL_LABEL, + (void*)&&ZEND_COUNT_SPEC_CV_UNUSED_LABEL, + (void*)&&ZEND_NULL_LABEL, + (void*)&&ZEND_NULL_LABEL, (void*)&&ZEND_ADD_LONG_NO_OVERFLOW_SPEC_CONST_TMPVARCV_LABEL, (void*)&&ZEND_ADD_LONG_NO_OVERFLOW_SPEC_CONST_TMPVARCV_LABEL, (void*)&&ZEND_NULL_LABEL, @@ -59461,6 +59670,9 @@ ZEND_API void execute_ex(zend_execute_data *ex) HYBRID_CASE(ZEND_YIELD_SPEC_CONST_UNUSED): ZEND_YIELD_SPEC_CONST_UNUSED_HANDLER(ZEND_OPCODE_HANDLER_ARGS_PASSTHRU); HYBRID_BREAK(); + HYBRID_CASE(ZEND_COUNT_SPEC_CONST_UNUSED): + ZEND_COUNT_SPEC_CONST_UNUSED_HANDLER(ZEND_OPCODE_HANDLER_ARGS_PASSTHRU); + HYBRID_BREAK(); HYBRID_CASE(ZEND_ADD_SPEC_CONST_CV): ZEND_ADD_SPEC_CONST_CV_HANDLER(ZEND_OPCODE_HANDLER_ARGS_PASSTHRU); HYBRID_BREAK(); @@ -59896,6 +60108,9 @@ ZEND_API void execute_ex(zend_execute_data *ex) HYBRID_CASE(ZEND_YIELD_SPEC_TMP_UNUSED): ZEND_YIELD_SPEC_TMP_UNUSED_HANDLER(ZEND_OPCODE_HANDLER_ARGS_PASSTHRU); HYBRID_BREAK(); + HYBRID_CASE(ZEND_COUNT_SPEC_TMP_UNUSED): + ZEND_COUNT_SPEC_TMP_UNUSED_HANDLER(ZEND_OPCODE_HANDLER_ARGS_PASSTHRU); + HYBRID_BREAK(); HYBRID_CASE(ZEND_IS_IDENTICAL_SPEC_TMP_CV): ZEND_IS_IDENTICAL_SPEC_TMP_CV_HANDLER(ZEND_OPCODE_HANDLER_ARGS_PASSTHRU); HYBRID_BREAK(); @@ -60364,6 +60579,9 @@ ZEND_API void execute_ex(zend_execute_data *ex) HYBRID_CASE(ZEND_MAKE_REF_SPEC_VAR_UNUSED): ZEND_MAKE_REF_SPEC_VAR_UNUSED_HANDLER(ZEND_OPCODE_HANDLER_ARGS_PASSTHRU); HYBRID_BREAK(); + HYBRID_CASE(ZEND_COUNT_SPEC_VAR_UNUSED): + ZEND_COUNT_SPEC_VAR_UNUSED_HANDLER(ZEND_OPCODE_HANDLER_ARGS_PASSTHRU); + HYBRID_BREAK(); HYBRID_CASE(ZEND_IS_IDENTICAL_SPEC_VAR_CV): ZEND_IS_IDENTICAL_SPEC_VAR_CV_HANDLER(ZEND_OPCODE_HANDLER_ARGS_PASSTHRU); HYBRID_BREAK(); @@ -61702,6 +61920,9 @@ ZEND_API void execute_ex(zend_execute_data *ex) HYBRID_CASE(ZEND_MAKE_REF_SPEC_CV_UNUSED): ZEND_MAKE_REF_SPEC_CV_UNUSED_HANDLER(ZEND_OPCODE_HANDLER_ARGS_PASSTHRU); HYBRID_BREAK(); + HYBRID_CASE(ZEND_COUNT_SPEC_CV_UNUSED): + ZEND_COUNT_SPEC_CV_UNUSED_HANDLER(ZEND_OPCODE_HANDLER_ARGS_PASSTHRU); + HYBRID_BREAK(); HYBRID_CASE(ZEND_ADD_SPEC_CV_CV): ZEND_ADD_SPEC_CV_CV_HANDLER(ZEND_OPCODE_HANDLER_ARGS_PASSTHRU); HYBRID_BREAK(); @@ -66633,6 +66854,31 @@ void zend_init_opcodes_handlers(void) ZEND_NULL_HANDLER, ZEND_NULL_HANDLER, ZEND_NULL_HANDLER, + ZEND_NULL_HANDLER, + ZEND_NULL_HANDLER, + ZEND_COUNT_SPEC_CONST_UNUSED_HANDLER, + ZEND_NULL_HANDLER, + ZEND_NULL_HANDLER, + ZEND_NULL_HANDLER, + ZEND_NULL_HANDLER, + ZEND_COUNT_SPEC_TMP_UNUSED_HANDLER, + ZEND_NULL_HANDLER, + ZEND_NULL_HANDLER, + ZEND_NULL_HANDLER, + ZEND_NULL_HANDLER, + ZEND_COUNT_SPEC_VAR_UNUSED_HANDLER, + ZEND_NULL_HANDLER, + ZEND_NULL_HANDLER, + ZEND_NULL_HANDLER, + ZEND_NULL_HANDLER, + ZEND_NULL_HANDLER, + ZEND_NULL_HANDLER, + ZEND_NULL_HANDLER, + ZEND_NULL_HANDLER, + ZEND_NULL_HANDLER, + ZEND_COUNT_SPEC_CV_UNUSED_HANDLER, + ZEND_NULL_HANDLER, + ZEND_NULL_HANDLER, ZEND_ADD_LONG_NO_OVERFLOW_SPEC_CONST_TMPVARCV_HANDLER, ZEND_ADD_LONG_NO_OVERFLOW_SPEC_CONST_TMPVARCV_HANDLER, ZEND_NULL_HANDLER, @@ -67700,7 +67946,7 @@ void zend_init_opcodes_handlers(void) 2257 | SPEC_RULE_OP1 | SPEC_RULE_OP2, 2282 | SPEC_RULE_OP1 | SPEC_RULE_OP2, 2307 | SPEC_RULE_OP1 | SPEC_RULE_OP2, - 4671, + 4696, 2332, 2333, 2334, @@ -67785,12 +68031,13 @@ void zend_init_opcodes_handlers(void) 3531 | SPEC_RULE_OP1 | SPEC_RULE_OP2, 3556 | SPEC_RULE_OP1 | SPEC_RULE_OP2, 3581 | SPEC_RULE_OP1 | SPEC_RULE_OP2, - 4671, + 4696, 3606 | SPEC_RULE_OP1 | SPEC_RULE_OP2, 3631 | SPEC_RULE_OP1 | SPEC_RULE_OP2, 3656 | SPEC_RULE_OP1 | SPEC_RULE_OP2, 3681 | SPEC_RULE_OP1 | SPEC_RULE_OP2, - 4671 + 3706 | SPEC_RULE_OP1 | SPEC_RULE_OP2, + 4696 }; #if (ZEND_VM_KIND == ZEND_VM_KIND_HYBRID) zend_opcode_handler_funcs = labels; @@ -67985,7 +68232,7 @@ ZEND_API void zend_vm_set_opcode_handler_ex(zend_op* op, uint32_t op1_info, uint if (op->op1_type == IS_CONST && op->op2_type == IS_CONST) { break; } - spec = 3706 | SPEC_RULE_OP1 | SPEC_RULE_OP2; + spec = 3731 | SPEC_RULE_OP1 | SPEC_RULE_OP2; if (op->op1_type > op->op2_type) { zend_swap_operands(op); } @@ -67993,7 +68240,7 @@ ZEND_API void zend_vm_set_opcode_handler_ex(zend_op* op, uint32_t op1_info, uint if (op->op1_type == IS_CONST && op->op2_type == IS_CONST) { break; } - spec = 3731 | SPEC_RULE_OP1 | SPEC_RULE_OP2; + spec = 3756 | SPEC_RULE_OP1 | SPEC_RULE_OP2; if (op->op1_type > op->op2_type) { zend_swap_operands(op); } @@ -68001,7 +68248,7 @@ ZEND_API void zend_vm_set_opcode_handler_ex(zend_op* op, uint32_t op1_info, uint if (op->op1_type == IS_CONST && op->op2_type == IS_CONST) { break; } - spec = 3756 | SPEC_RULE_OP1 | SPEC_RULE_OP2; + spec = 3781 | SPEC_RULE_OP1 | SPEC_RULE_OP2; if (op->op1_type > op->op2_type) { zend_swap_operands(op); } @@ -68012,17 +68259,17 @@ ZEND_API void zend_vm_set_opcode_handler_ex(zend_op* op, uint32_t op1_info, uint if (op->op1_type == IS_CONST && op->op2_type == IS_CONST) { break; } - spec = 3781 | SPEC_RULE_OP1 | SPEC_RULE_OP2; + spec = 3806 | SPEC_RULE_OP1 | SPEC_RULE_OP2; } else if (op1_info == MAY_BE_LONG && op2_info == MAY_BE_LONG) { if (op->op1_type == IS_CONST && op->op2_type == IS_CONST) { break; } - spec = 3806 | SPEC_RULE_OP1 | SPEC_RULE_OP2; + spec = 3831 | SPEC_RULE_OP1 | SPEC_RULE_OP2; } else if (op1_info == MAY_BE_DOUBLE && op2_info == MAY_BE_DOUBLE) { if (op->op1_type == IS_CONST && op->op2_type == IS_CONST) { break; } - spec = 3831 | SPEC_RULE_OP1 | SPEC_RULE_OP2; + spec = 3856 | SPEC_RULE_OP1 | SPEC_RULE_OP2; } break; case ZEND_MUL: @@ -68030,7 +68277,7 @@ ZEND_API void zend_vm_set_opcode_handler_ex(zend_op* op, uint32_t op1_info, uint if (op->op1_type == IS_CONST && op->op2_type == IS_CONST) { break; } - spec = 3856 | SPEC_RULE_OP1 | SPEC_RULE_OP2; + spec = 3881 | SPEC_RULE_OP1 | SPEC_RULE_OP2; if (op->op1_type > op->op2_type) { zend_swap_operands(op); } @@ -68038,7 +68285,7 @@ ZEND_API void zend_vm_set_opcode_handler_ex(zend_op* op, uint32_t op1_info, uint if (op->op1_type == IS_CONST && op->op2_type == IS_CONST) { break; } - spec = 3881 | SPEC_RULE_OP1 | SPEC_RULE_OP2; + spec = 3906 | SPEC_RULE_OP1 | SPEC_RULE_OP2; if (op->op1_type > op->op2_type) { zend_swap_operands(op); } @@ -68046,7 +68293,7 @@ ZEND_API void zend_vm_set_opcode_handler_ex(zend_op* op, uint32_t op1_info, uint if (op->op1_type == IS_CONST && op->op2_type == IS_CONST) { break; } - spec = 3906 | SPEC_RULE_OP1 | SPEC_RULE_OP2; + spec = 3931 | SPEC_RULE_OP1 | SPEC_RULE_OP2; if (op->op1_type > op->op2_type) { zend_swap_operands(op); } @@ -68057,7 +68304,7 @@ ZEND_API void zend_vm_set_opcode_handler_ex(zend_op* op, uint32_t op1_info, uint if (op->op1_type == IS_CONST && op->op2_type == IS_CONST) { break; } - spec = 3931 | SPEC_RULE_OP1 | SPEC_RULE_OP2 | SPEC_RULE_SMART_BRANCH; + spec = 3956 | SPEC_RULE_OP1 | SPEC_RULE_OP2 | SPEC_RULE_SMART_BRANCH; if (op->op1_type > op->op2_type) { zend_swap_operands(op); } @@ -68065,7 +68312,7 @@ ZEND_API void zend_vm_set_opcode_handler_ex(zend_op* op, uint32_t op1_info, uint if (op->op1_type == IS_CONST && op->op2_type == IS_CONST) { break; } - spec = 4006 | SPEC_RULE_OP1 | SPEC_RULE_OP2 | SPEC_RULE_SMART_BRANCH; + spec = 4031 | SPEC_RULE_OP1 | SPEC_RULE_OP2 | SPEC_RULE_SMART_BRANCH; if (op->op1_type > op->op2_type) { zend_swap_operands(op); } @@ -68076,7 +68323,7 @@ ZEND_API void zend_vm_set_opcode_handler_ex(zend_op* op, uint32_t op1_info, uint if (op->op1_type == IS_CONST && op->op2_type == IS_CONST) { break; } - spec = 4081 | SPEC_RULE_OP1 | SPEC_RULE_OP2 | SPEC_RULE_SMART_BRANCH; + spec = 4106 | SPEC_RULE_OP1 | SPEC_RULE_OP2 | SPEC_RULE_SMART_BRANCH; if (op->op1_type > op->op2_type) { zend_swap_operands(op); } @@ -68084,7 +68331,7 @@ ZEND_API void zend_vm_set_opcode_handler_ex(zend_op* op, uint32_t op1_info, uint if (op->op1_type == IS_CONST && op->op2_type == IS_CONST) { break; } - spec = 4156 | SPEC_RULE_OP1 | SPEC_RULE_OP2 | SPEC_RULE_SMART_BRANCH; + spec = 4181 | SPEC_RULE_OP1 | SPEC_RULE_OP2 | SPEC_RULE_SMART_BRANCH; if (op->op1_type > op->op2_type) { zend_swap_operands(op); } @@ -68095,12 +68342,12 @@ ZEND_API void zend_vm_set_opcode_handler_ex(zend_op* op, uint32_t op1_info, uint if (op->op1_type == IS_CONST && op->op2_type == IS_CONST) { break; } - spec = 4231 | SPEC_RULE_OP1 | SPEC_RULE_OP2 | SPEC_RULE_SMART_BRANCH; + spec = 4256 | SPEC_RULE_OP1 | SPEC_RULE_OP2 | SPEC_RULE_SMART_BRANCH; } else if (op1_info == MAY_BE_DOUBLE && op2_info == MAY_BE_DOUBLE) { if (op->op1_type == IS_CONST && op->op2_type == IS_CONST) { break; } - spec = 4306 | SPEC_RULE_OP1 | SPEC_RULE_OP2 | SPEC_RULE_SMART_BRANCH; + spec = 4331 | SPEC_RULE_OP1 | SPEC_RULE_OP2 | SPEC_RULE_SMART_BRANCH; } break; case ZEND_IS_SMALLER_OR_EQUAL: @@ -68108,70 +68355,70 @@ ZEND_API void zend_vm_set_opcode_handler_ex(zend_op* op, uint32_t op1_info, uint if (op->op1_type == IS_CONST && op->op2_type == IS_CONST) { break; } - spec = 4381 | SPEC_RULE_OP1 | SPEC_RULE_OP2 | SPEC_RULE_SMART_BRANCH; + spec = 4406 | SPEC_RULE_OP1 | SPEC_RULE_OP2 | SPEC_RULE_SMART_BRANCH; } else if (op1_info == MAY_BE_DOUBLE && op2_info == MAY_BE_DOUBLE) { if (op->op1_type == IS_CONST && op->op2_type == IS_CONST) { break; } - spec = 4456 | SPEC_RULE_OP1 | SPEC_RULE_OP2 | SPEC_RULE_SMART_BRANCH; + spec = 4481 | SPEC_RULE_OP1 | SPEC_RULE_OP2 | SPEC_RULE_SMART_BRANCH; } break; case ZEND_QM_ASSIGN: if (op1_info == MAY_BE_DOUBLE) { - spec = 4621 | SPEC_RULE_OP1; + spec = 4646 | SPEC_RULE_OP1; } else if (!(op1_info & ((MAY_BE_ANY|MAY_BE_UNDEF)-(MAY_BE_NULL|MAY_BE_FALSE|MAY_BE_TRUE|MAY_BE_LONG|MAY_BE_DOUBLE)))) { - spec = 4626 | SPEC_RULE_OP1; + spec = 4651 | SPEC_RULE_OP1; } break; case ZEND_PRE_INC: if (res_info == MAY_BE_LONG && op1_info == MAY_BE_LONG) { - spec = 4531 | SPEC_RULE_OP1 | SPEC_RULE_RETVAL; + spec = 4556 | SPEC_RULE_OP1 | SPEC_RULE_RETVAL; } else if (op1_info == MAY_BE_LONG) { - spec = 4541 | SPEC_RULE_OP1 | SPEC_RULE_RETVAL; + spec = 4566 | SPEC_RULE_OP1 | SPEC_RULE_RETVAL; } else if (op1_info == (MAY_BE_LONG|MAY_BE_DOUBLE)) { - spec = 4551 | SPEC_RULE_OP1 | SPEC_RULE_RETVAL; + spec = 4576 | SPEC_RULE_OP1 | SPEC_RULE_RETVAL; } break; case ZEND_PRE_DEC: if (res_info == MAY_BE_LONG && op1_info == MAY_BE_LONG) { - spec = 4561 | SPEC_RULE_OP1 | SPEC_RULE_RETVAL; + spec = 4586 | SPEC_RULE_OP1 | SPEC_RULE_RETVAL; } else if (op1_info == MAY_BE_LONG) { - spec = 4571 | SPEC_RULE_OP1 | SPEC_RULE_RETVAL; + spec = 4596 | SPEC_RULE_OP1 | SPEC_RULE_RETVAL; } else if (op1_info == (MAY_BE_LONG|MAY_BE_DOUBLE)) { - spec = 4581 | SPEC_RULE_OP1 | SPEC_RULE_RETVAL; + spec = 4606 | SPEC_RULE_OP1 | SPEC_RULE_RETVAL; } break; case ZEND_POST_INC: if (res_info == MAY_BE_LONG && op1_info == MAY_BE_LONG) { - spec = 4591 | SPEC_RULE_OP1; + spec = 4616 | SPEC_RULE_OP1; } else if (op1_info == MAY_BE_LONG) { - spec = 4596 | SPEC_RULE_OP1; + spec = 4621 | SPEC_RULE_OP1; } else if (op1_info == (MAY_BE_LONG|MAY_BE_DOUBLE)) { - spec = 4601 | SPEC_RULE_OP1; + spec = 4626 | SPEC_RULE_OP1; } break; case ZEND_POST_DEC: if (res_info == MAY_BE_LONG && op1_info == MAY_BE_LONG) { - spec = 4606 | SPEC_RULE_OP1; + spec = 4631 | SPEC_RULE_OP1; } else if (op1_info == MAY_BE_LONG) { - spec = 4611 | SPEC_RULE_OP1; + spec = 4636 | SPEC_RULE_OP1; } else if (op1_info == (MAY_BE_LONG|MAY_BE_DOUBLE)) { - spec = 4616 | SPEC_RULE_OP1; + spec = 4641 | SPEC_RULE_OP1; } break; case ZEND_SEND_VAR_EX: if ((op1_info & (MAY_BE_UNDEF|MAY_BE_REF)) == 0) { - spec = 4661 | SPEC_RULE_OP1 | SPEC_RULE_QUICK_ARG; + spec = 4686 | SPEC_RULE_OP1 | SPEC_RULE_QUICK_ARG; } 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))) { - spec = 4631 | SPEC_RULE_OP1 | SPEC_RULE_OP2; + spec = 4656 | SPEC_RULE_OP1 | SPEC_RULE_OP2; } break; case ZEND_SEND_VAR: if ((op1_info & (MAY_BE_UNDEF|MAY_BE_REF)) == 0) { - spec = 4656 | SPEC_RULE_OP1; + spec = 4681 | SPEC_RULE_OP1; } break; default: diff --git a/Zend/zend_vm_opcodes.c b/Zend/zend_vm_opcodes.c index eba840096d..22349193f9 100644 --- a/Zend/zend_vm_opcodes.c +++ b/Zend/zend_vm_opcodes.c @@ -21,7 +21,7 @@ #include #include -static const char *zend_vm_opcodes_names[190] = { +static const char *zend_vm_opcodes_names[191] = { "ZEND_NOP", "ZEND_ADD", "ZEND_SUB", @@ -212,9 +212,10 @@ static const char *zend_vm_opcodes_names[190] = { "ZEND_SWITCH_LONG", "ZEND_SWITCH_STRING", "ZEND_IN_ARRAY", + "ZEND_COUNT", }; -static uint32_t zend_vm_opcodes_flags[190] = { +static uint32_t zend_vm_opcodes_flags[191] = { 0x00000000, 0x00000707, 0x00000707, @@ -405,6 +406,7 @@ static uint32_t zend_vm_opcodes_flags[190] = { 0x03000307, 0x03000307, 0x01000303, + 0x00000103, }; ZEND_API const char* zend_get_opcode_name(zend_uchar opcode) { diff --git a/Zend/zend_vm_opcodes.h b/Zend/zend_vm_opcodes.h index 299a3c2ebc..60a1a26168 100644 --- a/Zend/zend_vm_opcodes.h +++ b/Zend/zend_vm_opcodes.h @@ -261,7 +261,8 @@ END_EXTERN_C() #define ZEND_SWITCH_LONG 187 #define ZEND_SWITCH_STRING 188 #define ZEND_IN_ARRAY 189 +#define ZEND_COUNT 190 -#define ZEND_VM_LAST_OPCODE 189 +#define ZEND_VM_LAST_OPCODE 190 #endif diff --git a/ext/opcache/Optimizer/zend_inference.c b/ext/opcache/Optimizer/zend_inference.c index 5c064be607..01d40bf15d 100644 --- a/ext/opcache/Optimizer/zend_inference.c +++ b/ext/opcache/Optimizer/zend_inference.c @@ -1353,6 +1353,10 @@ int zend_inference_calc_range(const zend_op_array *op_array, zend_ssa *ssa, int return 1; } break; + case ZEND_COUNT: + tmp->min = 0; + tmp->max = ZEND_LONG_MAX; + return 1; case ZEND_DO_FCALL: case ZEND_DO_ICALL: case ZEND_DO_UCALL: @@ -3156,6 +3160,9 @@ static void zend_update_type_info(const zend_op_array *op_array, } UPDATE_SSA_TYPE(tmp, ssa_ops[i].result_def); break; + case ZEND_COUNT: + UPDATE_SSA_TYPE(MAY_BE_LONG, ssa_ops[i].result_def); + break; case ZEND_TYPE_CHECK: case ZEND_DEFINED: UPDATE_SSA_TYPE(MAY_BE_FALSE|MAY_BE_TRUE, ssa_ops[i].result_def);