Don't optimize trailing args for prototype fbc

This commit is contained in:
Nikita Popov 2022-04-18 17:56:30 +02:00
parent c3a30544ad
commit 11f950e77e
2 changed files with 40 additions and 4 deletions

View file

@ -149,6 +149,20 @@ static void zend_try_inline_call(zend_op_array *op_array, zend_op *fcall, zend_o
} }
} }
/* arg_num is 1-based here, to match SEND encoding. */
static bool has_known_send_mode(const optimizer_call_info *info, uint32_t arg_num)
{
if (!info->func) {
return false;
}
/* For prototype functions we should not make assumptions about arguments that are not part of
* the signature: And inheriting method can add an optional by-ref argument. */
return !info->is_prototype
|| arg_num <= info->func->common.num_args
|| (info->func->common.fn_flags & ZEND_ACC_VARIADIC);
}
void zend_optimize_func_calls(zend_op_array *op_array, zend_optimizer_ctx *ctx) void zend_optimize_func_calls(zend_op_array *op_array, zend_optimizer_ctx *ctx)
{ {
zend_op *opline = op_array->opcodes; zend_op *opline = op_array->opcodes;
@ -261,7 +275,7 @@ void zend_optimize_func_calls(zend_op_array *op_array, zend_optimizer_ctx *ctx)
} }
break; break;
case ZEND_SEND_VAL_EX: case ZEND_SEND_VAL_EX:
if (call_stack[call - 1].func) { if (has_known_send_mode(&call_stack[call - 1], opline->op2.num)) {
if (opline->op2_type == IS_CONST) { if (opline->op2_type == IS_CONST) {
call_stack[call - 1].try_inline = 0; call_stack[call - 1].try_inline = 0;
break; break;
@ -276,7 +290,7 @@ void zend_optimize_func_calls(zend_op_array *op_array, zend_optimizer_ctx *ctx)
} }
break; break;
case ZEND_CHECK_FUNC_ARG: case ZEND_CHECK_FUNC_ARG:
if (call_stack[call - 1].func) { if (has_known_send_mode(&call_stack[call - 1], opline->op2.num)) {
if (opline->op2_type == IS_CONST) { if (opline->op2_type == IS_CONST) {
call_stack[call - 1].try_inline = 0; call_stack[call - 1].try_inline = 0;
call_stack[call - 1].func_arg_num = (uint32_t)-1; call_stack[call - 1].func_arg_num = (uint32_t)-1;
@ -289,7 +303,7 @@ void zend_optimize_func_calls(zend_op_array *op_array, zend_optimizer_ctx *ctx)
break; break;
case ZEND_SEND_VAR_EX: case ZEND_SEND_VAR_EX:
case ZEND_SEND_FUNC_ARG: case ZEND_SEND_FUNC_ARG:
if (call_stack[call - 1].func) { if (has_known_send_mode(&call_stack[call - 1], opline->op2.num)) {
if (opline->op2_type == IS_CONST) { if (opline->op2_type == IS_CONST) {
call_stack[call - 1].try_inline = 0; call_stack[call - 1].try_inline = 0;
break; break;
@ -304,7 +318,7 @@ void zend_optimize_func_calls(zend_op_array *op_array, zend_optimizer_ctx *ctx)
} }
break; break;
case ZEND_SEND_VAR_NO_REF_EX: case ZEND_SEND_VAR_NO_REF_EX:
if (call_stack[call - 1].func) { if (has_known_send_mode(&call_stack[call - 1], opline->op2.num)) {
if (opline->op2_type == IS_CONST) { if (opline->op2_type == IS_CONST) {
call_stack[call - 1].try_inline = 0; call_stack[call - 1].try_inline = 0;
break; break;

View file

@ -0,0 +1,22 @@
--TEST--
Adding an optional by-ref arg in a child method
--FILE--
<?php
class Test1 {
public function method1() {
$this->method2($x);
var_dump($x);
}
public function method2() {}
}
class Test2 extends Test1 {
public function method2(&$x = null) {
++$x;
}
}
(new Test2)->method1();
?>
--EXPECT--
int(1)