From 6043f76ad7f00dc4e7c4d45ac2f0cdb3db9f63ac Mon Sep 17 00:00:00 2001 From: Dmitry Stogov Date: Tue, 30 May 2017 13:23:17 +0300 Subject: [PATCH] Added ZEND_FUNC_NUM_ARGS, ZEND_FUNC_GET_ARGS instructions, to implement corresponding builtin functions. Special optimisation for "array_slice(INT, func_get_args())" pattern. --- NEWS | 5 +- Zend/zend_compile.c | 57 +++++ Zend/zend_vm_def.h | 72 ++++++ Zend/zend_vm_execute.h | 323 ++++++++++++++++++++++--- Zend/zend_vm_opcodes.c | 8 +- Zend/zend_vm_opcodes.h | 4 +- ext/opcache/Optimizer/zend_func_info.c | 2 +- ext/opcache/Optimizer/zend_inference.c | 5 + 8 files changed, 433 insertions(+), 43 deletions(-) diff --git a/NEWS b/NEWS index 56f25666a9..8f07dbe761 100644 --- a/NEWS +++ b/NEWS @@ -3,8 +3,9 @@ PHP NEWS ?? ??? ????, PHP 7.2 - Core: - . Added ZEND_COUNT, ZEND_GET_CLASS, ZEND_GET_CALLED_CLASS, ZEND_GET_TYPE - instructions, to implement corresponding builtin functions. (Dmitry) + . Added ZEND_COUNT, ZEND_GET_CLASS, ZEND_GET_CALLED_CLASS, ZEND_GET_TYPE, + ZEND_FUNC_NUM_ARGS, ZEND_FUNC_GET_ARGS instructions, to implement + corresponding builtin functions. (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 e210a26e43..43e65f0ede 100644 --- a/Zend/zend_compile.c +++ b/Zend/zend_compile.c @@ -3807,6 +3807,57 @@ int zend_compile_func_gettype(znode *result, zend_ast_list *args) /* {{{ */ } /* }}} */ +int zend_compile_func_num_args(znode *result, zend_ast_list *args) /* {{{ */ +{ + if (CG(active_op_array)->function_name && args->children == 0) { + zend_emit_op_tmp(result, ZEND_FUNC_NUM_ARGS, NULL, NULL); + return SUCCESS; + } else { + return FAILURE; + } +} +/* }}} */ + +int zend_compile_func_get_args(znode *result, zend_ast_list *args) /* {{{ */ +{ + if (CG(active_op_array)->function_name && args->children == 0) { + zend_emit_op_tmp(result, ZEND_FUNC_GET_ARGS, NULL, NULL); + return SUCCESS; + } else { + return FAILURE; + } +} +/* }}} */ + +int zend_compile_func_array_slice(znode *result, zend_ast_list *args) /* {{{ */ +{ + if (CG(active_op_array)->function_name + && args->children == 2 + && args->child[0]->kind == ZEND_AST_CALL + && args->child[0]->child[0]->kind == ZEND_AST_ZVAL + && args->child[0]->child[1]->kind == ZEND_AST_ARG_LIST + && args->child[1]->kind == ZEND_AST_ZVAL) { + + zval *name = zend_ast_get_zval(args->child[0]->child[0]); + zend_ast_list *list = zend_ast_get_list(args->child[0]->child[1]); + zval *zv = zend_ast_get_zval(args->child[1]); + znode first; + + if (Z_TYPE_P(name) == IS_STRING + && zend_string_equals_literal_ci(Z_STR_P(name), "func_get_args") + && list->children == 0 + && Z_TYPE_P(zv) == IS_LONG + && Z_LVAL_P(zv) >= 0) { + first.op_type = IS_CONST; + ZVAL_LONG(&first.u.constant, Z_LVAL_P(zv)); + zend_emit_op_tmp(result, ZEND_FUNC_GET_ARGS, &first, NULL); + return SUCCESS; + } + } + return FAILURE; +} +/* }}} */ + 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)) { @@ -3875,6 +3926,12 @@ int zend_try_compile_special_func(znode *result, zend_string *lcname, zend_ast_l return zend_compile_func_get_called_class(result, args); } else if (zend_string_equals_literal(lcname, "gettype")) { return zend_compile_func_gettype(result, args); + } else if (zend_string_equals_literal(lcname, "func_num_args")) { + return zend_compile_func_num_args(result, args); + } else if (zend_string_equals_literal(lcname, "func_get_args")) { + return zend_compile_func_get_args(result, args); + } else if (zend_string_equals_literal(lcname, "array_slice")) { + return zend_compile_func_array_slice(result, args); } else { return FAILURE; } diff --git a/Zend/zend_vm_def.h b/Zend/zend_vm_def.h index d26f9e78cb..bd82456661 100644 --- a/Zend/zend_vm_def.h +++ b/Zend/zend_vm_def.h @@ -8311,6 +8311,78 @@ ZEND_VM_HANDLER(193, ZEND_GET_TYPE, CONST|TMP|VAR|CV, UNUSED) ZEND_VM_NEXT_OPCODE_CHECK_EXCEPTION(); } +ZEND_VM_HANDLER(194, ZEND_FUNC_NUM_ARGS, UNUSED, UNUSED) +{ + ZVAL_LONG(EX_VAR(opline->result.var), EX_NUM_ARGS()); + ZEND_VM_NEXT_OPCODE(); +} + +ZEND_VM_HANDLER(195, ZEND_FUNC_GET_ARGS, UNUSED|CONST, UNUSED) +{ + USE_OPLINE + zend_array *ht; + uint32_t arg_count, first_extra_arg, i, n; + zval *p, *q; + + arg_count = EX_NUM_ARGS(); + ht = (zend_array *) emalloc(sizeof(zend_array)); + if (OP1_TYPE == IS_CONST) { + i = Z_LVAL_P(EX_CONSTANT(opline->op1)); + if (arg_count < i) { + i = 0; + } else { + i = arg_count - i; + } + zend_hash_init(ht, i, NULL, ZVAL_PTR_DTOR, 0); + } else { + zend_hash_init(ht, arg_count, NULL, ZVAL_PTR_DTOR, 0); + } + ZVAL_ARR(EX_VAR(opline->result.var), ht); + if (arg_count) { + first_extra_arg = EX(func)->op_array.num_args; + zend_hash_real_init(ht, 1); + ZEND_HASH_FILL_PACKED(ht) { + i = 0; + n = 0; + if (OP1_TYPE == IS_CONST) { + i = Z_LVAL_P(EX_CONSTANT(opline->op1)); + } + p = EX_VAR_NUM(i); + if (arg_count > first_extra_arg) { + while (i < first_extra_arg) { + q = p; + if (EXPECTED(Z_TYPE_INFO_P(q) != IS_UNDEF)) { + ZVAL_DEREF(q); + if (Z_OPT_REFCOUNTED_P(q)) { + Z_ADDREF_P(q); + } + n++; + } + ZEND_HASH_FILL_ADD(q); + p++; + i++; + } + p = EX_VAR_NUM(EX(func)->op_array.last_var + EX(func)->op_array.T); + } + while (i < arg_count) { + q = p; + if (EXPECTED(Z_TYPE_INFO_P(q) != IS_UNDEF)) { + ZVAL_DEREF(q); + if (Z_OPT_REFCOUNTED_P(q)) { + Z_ADDREF_P(q); + } + n++; + } + ZEND_HASH_FILL_ADD(q); + p++; + i++; + } + } ZEND_HASH_FILL_END(); + ht->nNumOfElements = n; + } + ZEND_VM_NEXT_OPCODE(); +} + 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 2427327af6..c6ceb078f4 100644 --- a/Zend/zend_vm_execute.h +++ b/Zend/zend_vm_execute.h @@ -8219,6 +8219,72 @@ static ZEND_OPCODE_HANDLER_RET ZEND_FASTCALL ZEND_GET_TYPE_SPEC_CONST_UNUSED_HAN ZEND_VM_NEXT_OPCODE_CHECK_EXCEPTION(); } +static ZEND_OPCODE_HANDLER_RET ZEND_FASTCALL ZEND_FUNC_GET_ARGS_SPEC_CONST_UNUSED_HANDLER(ZEND_OPCODE_HANDLER_ARGS) +{ + USE_OPLINE + zend_array *ht; + uint32_t arg_count, first_extra_arg, i, n; + zval *p, *q; + + arg_count = EX_NUM_ARGS(); + ht = (zend_array *) emalloc(sizeof(zend_array)); + if (IS_CONST == IS_CONST) { + i = Z_LVAL_P(EX_CONSTANT(opline->op1)); + if (arg_count < i) { + i = 0; + } else { + i = arg_count - i; + } + zend_hash_init(ht, i, NULL, ZVAL_PTR_DTOR, 0); + } else { + zend_hash_init(ht, arg_count, NULL, ZVAL_PTR_DTOR, 0); + } + ZVAL_ARR(EX_VAR(opline->result.var), ht); + if (arg_count) { + first_extra_arg = EX(func)->op_array.num_args; + zend_hash_real_init(ht, 1); + ZEND_HASH_FILL_PACKED(ht) { + i = 0; + n = 0; + if (IS_CONST == IS_CONST) { + i = Z_LVAL_P(EX_CONSTANT(opline->op1)); + } + p = EX_VAR_NUM(i); + if (arg_count > first_extra_arg) { + while (i < first_extra_arg) { + q = p; + if (EXPECTED(Z_TYPE_INFO_P(q) != IS_UNDEF)) { + ZVAL_DEREF(q); + if (Z_OPT_REFCOUNTED_P(q)) { + Z_ADDREF_P(q); + } + n++; + } + ZEND_HASH_FILL_ADD(q); + p++; + i++; + } + p = EX_VAR_NUM(EX(func)->op_array.last_var + EX(func)->op_array.T); + } + while (i < arg_count) { + q = p; + if (EXPECTED(Z_TYPE_INFO_P(q) != IS_UNDEF)) { + ZVAL_DEREF(q); + if (Z_OPT_REFCOUNTED_P(q)) { + Z_ADDREF_P(q); + } + n++; + } + ZEND_HASH_FILL_ADD(q); + p++; + i++; + } + } ZEND_HASH_FILL_END(); + ht->nNumOfElements = n; + } + ZEND_VM_NEXT_OPCODE(); +} + static ZEND_OPCODE_HANDLER_RET ZEND_FASTCALL ZEND_ADD_SPEC_CONST_CV_HANDLER(ZEND_OPCODE_HANDLER_ARGS) { USE_OPLINE @@ -29517,6 +29583,78 @@ static ZEND_OPCODE_HANDLER_RET ZEND_FASTCALL ZEND_GET_CALLED_CLASS_SPEC_UNUSED_U ZEND_VM_NEXT_OPCODE(); } +static ZEND_OPCODE_HANDLER_RET ZEND_FASTCALL ZEND_FUNC_NUM_ARGS_SPEC_UNUSED_UNUSED_HANDLER(ZEND_OPCODE_HANDLER_ARGS) +{ + ZVAL_LONG(EX_VAR(opline->result.var), EX_NUM_ARGS()); + ZEND_VM_NEXT_OPCODE(); +} + +static ZEND_OPCODE_HANDLER_RET ZEND_FASTCALL ZEND_FUNC_GET_ARGS_SPEC_UNUSED_UNUSED_HANDLER(ZEND_OPCODE_HANDLER_ARGS) +{ + USE_OPLINE + zend_array *ht; + uint32_t arg_count, first_extra_arg, i, n; + zval *p, *q; + + arg_count = EX_NUM_ARGS(); + ht = (zend_array *) emalloc(sizeof(zend_array)); + if (IS_UNUSED == IS_CONST) { + i = Z_LVAL_P(EX_CONSTANT(opline->op1)); + if (arg_count < i) { + i = 0; + } else { + i = arg_count - i; + } + zend_hash_init(ht, i, NULL, ZVAL_PTR_DTOR, 0); + } else { + zend_hash_init(ht, arg_count, NULL, ZVAL_PTR_DTOR, 0); + } + ZVAL_ARR(EX_VAR(opline->result.var), ht); + if (arg_count) { + first_extra_arg = EX(func)->op_array.num_args; + zend_hash_real_init(ht, 1); + ZEND_HASH_FILL_PACKED(ht) { + i = 0; + n = 0; + if (IS_UNUSED == IS_CONST) { + i = Z_LVAL_P(EX_CONSTANT(opline->op1)); + } + p = EX_VAR_NUM(i); + if (arg_count > first_extra_arg) { + while (i < first_extra_arg) { + q = p; + if (EXPECTED(Z_TYPE_INFO_P(q) != IS_UNDEF)) { + ZVAL_DEREF(q); + if (Z_OPT_REFCOUNTED_P(q)) { + Z_ADDREF_P(q); + } + n++; + } + ZEND_HASH_FILL_ADD(q); + p++; + i++; + } + p = EX_VAR_NUM(EX(func)->op_array.last_var + EX(func)->op_array.T); + } + while (i < arg_count) { + q = p; + if (EXPECTED(Z_TYPE_INFO_P(q) != IS_UNDEF)) { + ZVAL_DEREF(q); + if (Z_OPT_REFCOUNTED_P(q)) { + Z_ADDREF_P(q); + } + n++; + } + ZEND_HASH_FILL_ADD(q); + p++; + i++; + } + } ZEND_HASH_FILL_END(); + ht->nNumOfElements = n; + } + ZEND_VM_NEXT_OPCODE(); +} + static ZEND_OPCODE_HANDLER_RET ZEND_FASTCALL zend_binary_assign_op_obj_helper_SPEC_UNUSED_CV(binary_op_type binary_op ZEND_OPCODE_HANDLER_ARGS_DC) { USE_OPLINE @@ -58544,6 +58682,56 @@ ZEND_API void execute_ex(zend_execute_data *ex) (void*)&&ZEND_GET_TYPE_SPEC_CV_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_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_NULL_LABEL, + (void*)&&ZEND_FUNC_NUM_ARGS_SPEC_UNUSED_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_FUNC_GET_ARGS_SPEC_CONST_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_NULL_LABEL, + (void*)&&ZEND_NULL_LABEL, + (void*)&&ZEND_NULL_LABEL, + (void*)&&ZEND_NULL_LABEL, + (void*)&&ZEND_NULL_LABEL, + (void*)&&ZEND_FUNC_GET_ARGS_SPEC_UNUSED_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_ADD_LONG_NO_OVERFLOW_SPEC_CONST_TMPVARCV_LABEL, (void*)&&ZEND_ADD_LONG_NO_OVERFLOW_SPEC_CONST_TMPVARCV_LABEL, (void*)&&ZEND_NULL_LABEL, @@ -60058,6 +60246,9 @@ ZEND_API void execute_ex(zend_execute_data *ex) HYBRID_CASE(ZEND_GET_TYPE_SPEC_CONST_UNUSED): ZEND_GET_TYPE_SPEC_CONST_UNUSED_HANDLER(ZEND_OPCODE_HANDLER_ARGS_PASSTHRU); HYBRID_BREAK(); + HYBRID_CASE(ZEND_FUNC_GET_ARGS_SPEC_CONST_UNUSED): + ZEND_FUNC_GET_ARGS_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(); @@ -61507,6 +61698,12 @@ ZEND_API void execute_ex(zend_execute_data *ex) HYBRID_CASE(ZEND_GET_CALLED_CLASS_SPEC_UNUSED_UNUSED): ZEND_GET_CALLED_CLASS_SPEC_UNUSED_UNUSED_HANDLER(ZEND_OPCODE_HANDLER_ARGS_PASSTHRU); HYBRID_BREAK(); + HYBRID_CASE(ZEND_FUNC_NUM_ARGS_SPEC_UNUSED_UNUSED): + ZEND_FUNC_NUM_ARGS_SPEC_UNUSED_UNUSED_HANDLER(ZEND_OPCODE_HANDLER_ARGS_PASSTHRU); + HYBRID_BREAK(); + HYBRID_CASE(ZEND_FUNC_GET_ARGS_SPEC_UNUSED_UNUSED): + ZEND_FUNC_GET_ARGS_SPEC_UNUSED_UNUSED_HANDLER(ZEND_OPCODE_HANDLER_ARGS_PASSTHRU); + HYBRID_BREAK(); HYBRID_CASE(ZEND_ASSIGN_ADD_SPEC_UNUSED_CV_OBJ): ZEND_ASSIGN_ADD_SPEC_UNUSED_CV_OBJ_HANDLER(ZEND_OPCODE_HANDLER_ARGS_PASSTHRU); HYBRID_BREAK(); @@ -67363,6 +67560,56 @@ void zend_init_opcodes_handlers(void) ZEND_GET_TYPE_SPEC_CV_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_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_NULL_HANDLER, + ZEND_FUNC_NUM_ARGS_SPEC_UNUSED_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_FUNC_GET_ARGS_SPEC_CONST_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_NULL_HANDLER, + ZEND_NULL_HANDLER, + ZEND_NULL_HANDLER, + ZEND_NULL_HANDLER, + ZEND_NULL_HANDLER, + ZEND_FUNC_GET_ARGS_SPEC_UNUSED_UNUSED_HANDLER, + ZEND_NULL_HANDLER, + ZEND_NULL_HANDLER, + ZEND_NULL_HANDLER, + ZEND_NULL_HANDLER, + ZEND_NULL_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, @@ -68430,7 +68677,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, - 4771, + 4821, 2332, 2333, 2334, @@ -68515,7 +68762,7 @@ 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, - 4771, + 4821, 3606 | SPEC_RULE_OP1 | SPEC_RULE_OP2, 3631 | SPEC_RULE_OP1 | SPEC_RULE_OP2, 3656 | SPEC_RULE_OP1 | SPEC_RULE_OP2, @@ -68524,7 +68771,9 @@ void zend_init_opcodes_handlers(void) 3731 | SPEC_RULE_OP1 | SPEC_RULE_OP2, 3756 | SPEC_RULE_OP1 | SPEC_RULE_OP2, 3781 | SPEC_RULE_OP1 | SPEC_RULE_OP2, - 4771 + 3806 | SPEC_RULE_OP1 | SPEC_RULE_OP2, + 3831 | SPEC_RULE_OP1 | SPEC_RULE_OP2, + 4821 }; #if (ZEND_VM_KIND == ZEND_VM_KIND_HYBRID) zend_opcode_handler_funcs = labels; @@ -68719,7 +68968,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 = 3806 | SPEC_RULE_OP1 | SPEC_RULE_OP2; + spec = 3856 | SPEC_RULE_OP1 | SPEC_RULE_OP2; if (op->op1_type > op->op2_type) { zend_swap_operands(op); } @@ -68727,7 +68976,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 = 3831 | 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); } @@ -68735,7 +68984,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 = 3906 | SPEC_RULE_OP1 | SPEC_RULE_OP2; if (op->op1_type > op->op2_type) { zend_swap_operands(op); } @@ -68746,17 +68995,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 = 3881 | SPEC_RULE_OP1 | SPEC_RULE_OP2; + spec = 3931 | 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 = 3906 | SPEC_RULE_OP1 | SPEC_RULE_OP2; + spec = 3956 | 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 = 3931 | SPEC_RULE_OP1 | SPEC_RULE_OP2; + spec = 3981 | SPEC_RULE_OP1 | SPEC_RULE_OP2; } break; case ZEND_MUL: @@ -68764,7 +69013,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 = 3956 | SPEC_RULE_OP1 | SPEC_RULE_OP2; + spec = 4006 | SPEC_RULE_OP1 | SPEC_RULE_OP2; if (op->op1_type > op->op2_type) { zend_swap_operands(op); } @@ -68772,7 +69021,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 = 3981 | SPEC_RULE_OP1 | SPEC_RULE_OP2; + spec = 4031 | SPEC_RULE_OP1 | SPEC_RULE_OP2; if (op->op1_type > op->op2_type) { zend_swap_operands(op); } @@ -68780,7 +69029,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 = 4056 | SPEC_RULE_OP1 | SPEC_RULE_OP2; if (op->op1_type > op->op2_type) { zend_swap_operands(op); } @@ -68791,7 +69040,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 = 4031 | SPEC_RULE_OP1 | SPEC_RULE_OP2 | SPEC_RULE_SMART_BRANCH; + spec = 4081 | SPEC_RULE_OP1 | SPEC_RULE_OP2 | SPEC_RULE_SMART_BRANCH; if (op->op1_type > op->op2_type) { zend_swap_operands(op); } @@ -68799,7 +69048,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 = 4106 | SPEC_RULE_OP1 | SPEC_RULE_OP2 | SPEC_RULE_SMART_BRANCH; + spec = 4156 | SPEC_RULE_OP1 | SPEC_RULE_OP2 | SPEC_RULE_SMART_BRANCH; if (op->op1_type > op->op2_type) { zend_swap_operands(op); } @@ -68810,7 +69059,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 = 4181 | SPEC_RULE_OP1 | SPEC_RULE_OP2 | SPEC_RULE_SMART_BRANCH; + spec = 4231 | SPEC_RULE_OP1 | SPEC_RULE_OP2 | SPEC_RULE_SMART_BRANCH; if (op->op1_type > op->op2_type) { zend_swap_operands(op); } @@ -68818,7 +69067,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 = 4256 | SPEC_RULE_OP1 | SPEC_RULE_OP2 | SPEC_RULE_SMART_BRANCH; + spec = 4306 | SPEC_RULE_OP1 | SPEC_RULE_OP2 | SPEC_RULE_SMART_BRANCH; if (op->op1_type > op->op2_type) { zend_swap_operands(op); } @@ -68829,12 +69078,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 = 4331 | SPEC_RULE_OP1 | SPEC_RULE_OP2 | SPEC_RULE_SMART_BRANCH; + spec = 4381 | 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 = 4406 | SPEC_RULE_OP1 | SPEC_RULE_OP2 | SPEC_RULE_SMART_BRANCH; + spec = 4456 | SPEC_RULE_OP1 | SPEC_RULE_OP2 | SPEC_RULE_SMART_BRANCH; } break; case ZEND_IS_SMALLER_OR_EQUAL: @@ -68842,70 +69091,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 = 4481 | SPEC_RULE_OP1 | SPEC_RULE_OP2 | SPEC_RULE_SMART_BRANCH; + spec = 4531 | 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 = 4556 | SPEC_RULE_OP1 | SPEC_RULE_OP2 | SPEC_RULE_SMART_BRANCH; + spec = 4606 | SPEC_RULE_OP1 | SPEC_RULE_OP2 | SPEC_RULE_SMART_BRANCH; } break; case ZEND_QM_ASSIGN: if (op1_info == MAY_BE_DOUBLE) { - spec = 4721 | SPEC_RULE_OP1; + spec = 4771 | 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 = 4726 | SPEC_RULE_OP1; + spec = 4776 | SPEC_RULE_OP1; } break; case ZEND_PRE_INC: if (res_info == MAY_BE_LONG && op1_info == MAY_BE_LONG) { - spec = 4631 | SPEC_RULE_OP1 | SPEC_RULE_RETVAL; + spec = 4681 | SPEC_RULE_OP1 | SPEC_RULE_RETVAL; } else if (op1_info == MAY_BE_LONG) { - spec = 4641 | SPEC_RULE_OP1 | SPEC_RULE_RETVAL; + spec = 4691 | SPEC_RULE_OP1 | SPEC_RULE_RETVAL; } else if (op1_info == (MAY_BE_LONG|MAY_BE_DOUBLE)) { - spec = 4651 | SPEC_RULE_OP1 | SPEC_RULE_RETVAL; + spec = 4701 | SPEC_RULE_OP1 | SPEC_RULE_RETVAL; } break; case ZEND_PRE_DEC: if (res_info == MAY_BE_LONG && op1_info == MAY_BE_LONG) { - spec = 4661 | SPEC_RULE_OP1 | SPEC_RULE_RETVAL; + spec = 4711 | SPEC_RULE_OP1 | SPEC_RULE_RETVAL; } else if (op1_info == MAY_BE_LONG) { - spec = 4671 | SPEC_RULE_OP1 | SPEC_RULE_RETVAL; + spec = 4721 | SPEC_RULE_OP1 | SPEC_RULE_RETVAL; } else if (op1_info == (MAY_BE_LONG|MAY_BE_DOUBLE)) { - spec = 4681 | SPEC_RULE_OP1 | SPEC_RULE_RETVAL; + spec = 4731 | SPEC_RULE_OP1 | SPEC_RULE_RETVAL; } break; case ZEND_POST_INC: if (res_info == MAY_BE_LONG && op1_info == MAY_BE_LONG) { - spec = 4691 | SPEC_RULE_OP1; + spec = 4741 | SPEC_RULE_OP1; } else if (op1_info == MAY_BE_LONG) { - spec = 4696 | SPEC_RULE_OP1; + spec = 4746 | SPEC_RULE_OP1; } else if (op1_info == (MAY_BE_LONG|MAY_BE_DOUBLE)) { - spec = 4701 | SPEC_RULE_OP1; + spec = 4751 | SPEC_RULE_OP1; } break; case ZEND_POST_DEC: if (res_info == MAY_BE_LONG && op1_info == MAY_BE_LONG) { - spec = 4706 | SPEC_RULE_OP1; + spec = 4756 | SPEC_RULE_OP1; } else if (op1_info == MAY_BE_LONG) { - spec = 4711 | SPEC_RULE_OP1; + spec = 4761 | SPEC_RULE_OP1; } else if (op1_info == (MAY_BE_LONG|MAY_BE_DOUBLE)) { - spec = 4716 | SPEC_RULE_OP1; + spec = 4766 | SPEC_RULE_OP1; } break; case ZEND_SEND_VAR_EX: if ((op1_info & (MAY_BE_UNDEF|MAY_BE_REF)) == 0) { - spec = 4761 | SPEC_RULE_OP1 | SPEC_RULE_QUICK_ARG; + spec = 4811 | 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 = 4731 | SPEC_RULE_OP1 | SPEC_RULE_OP2; + spec = 4781 | SPEC_RULE_OP1 | SPEC_RULE_OP2; } break; case ZEND_SEND_VAR: if ((op1_info & (MAY_BE_UNDEF|MAY_BE_REF)) == 0) { - spec = 4756 | SPEC_RULE_OP1; + spec = 4806 | SPEC_RULE_OP1; } break; default: diff --git a/Zend/zend_vm_opcodes.c b/Zend/zend_vm_opcodes.c index 0d0fc51455..8a58a12450 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[194] = { +static const char *zend_vm_opcodes_names[196] = { "ZEND_NOP", "ZEND_ADD", "ZEND_SUB", @@ -216,9 +216,11 @@ static const char *zend_vm_opcodes_names[194] = { "ZEND_GET_CLASS", "ZEND_GET_CALLED_CLASS", "ZEND_GET_TYPE", + "ZEND_FUNC_NUM_ARGS", + "ZEND_FUNC_GET_ARGS", }; -static uint32_t zend_vm_opcodes_flags[194] = { +static uint32_t zend_vm_opcodes_flags[196] = { 0x00000000, 0x00000707, 0x00000707, @@ -413,6 +415,8 @@ static uint32_t zend_vm_opcodes_flags[194] = { 0x00000103, 0x00000101, 0x00000103, + 0x00000101, + 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 ed4bb73b27..6001400bf8 100644 --- a/Zend/zend_vm_opcodes.h +++ b/Zend/zend_vm_opcodes.h @@ -265,7 +265,9 @@ END_EXTERN_C() #define ZEND_GET_CLASS 191 #define ZEND_GET_CALLED_CLASS 192 #define ZEND_GET_TYPE 193 +#define ZEND_FUNC_NUM_ARGS 194 +#define ZEND_FUNC_GET_ARGS 195 -#define ZEND_VM_LAST_OPCODE 193 +#define ZEND_VM_LAST_OPCODE 195 #endif diff --git a/ext/opcache/Optimizer/zend_func_info.c b/ext/opcache/Optimizer/zend_func_info.c index f9992d539a..6cb55a11a8 100644 --- a/ext/opcache/Optimizer/zend_func_info.c +++ b/ext/opcache/Optimizer/zend_func_info.c @@ -224,7 +224,7 @@ static const func_info_t func_infos[] = { F0("gc_disable", MAY_BE_NULL), F0("func_num_args", MAY_BE_LONG), FN("func_get_arg", UNKNOWN_INFO), - F1("func_get_args", MAY_BE_FALSE | MAY_BE_ARRAY | MAY_BE_ARRAY_KEY_LONG | MAY_BE_ARRAY_OF_ANY | MAY_BE_ARRAY_OF_REF), + F1("func_get_args", MAY_BE_FALSE | MAY_BE_ARRAY | MAY_BE_ARRAY_KEY_LONG | MAY_BE_ARRAY_OF_ANY), FC("strlen", zend_strlen_info), FC("strcmp", zend_l_ss_info), FC("strncmp", zend_lb_ssn_info), diff --git a/ext/opcache/Optimizer/zend_inference.c b/ext/opcache/Optimizer/zend_inference.c index ee242c4253..3c3a810322 100644 --- a/ext/opcache/Optimizer/zend_inference.c +++ b/ext/opcache/Optimizer/zend_inference.c @@ -1354,6 +1354,7 @@ int zend_inference_calc_range(const zend_op_array *op_array, zend_ssa *ssa, int } break; case ZEND_COUNT: + case ZEND_FUNC_NUM_ARGS: tmp->min = 0; tmp->max = ZEND_LONG_MAX; return 1; @@ -3161,8 +3162,12 @@ 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: + case ZEND_FUNC_NUM_ARGS: UPDATE_SSA_TYPE(MAY_BE_LONG, ssa_ops[i].result_def); break; + case ZEND_FUNC_GET_ARGS: + UPDATE_SSA_TYPE(MAY_BE_ARRAY | MAY_BE_ARRAY_KEY_LONG | MAY_BE_ARRAY_OF_ANY, ssa_ops[i].result_def); + break; case ZEND_GET_CLASS: case ZEND_GET_CALLED_CLASS: UPDATE_SSA_TYPE(MAY_BE_FALSE|MAY_BE_STRING, ssa_ops[i].result_def); -- 2.50.1