Skip to content

Commit 7594558

Browse files
committed
Fix deoptimization after exit during inc/dec
When the assumption that (PRE|POST)_(INC|DEC) overflows turns out to be false and we exit, effects are lost if op1 or result were in regs. Fix by updating the stack map before creating the exit point. Fixes GH-19669 Closes GH-19680
1 parent 51033c2 commit 7594558

File tree

4 files changed

+64
-15
lines changed

4 files changed

+64
-15
lines changed

NEWS

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -7,6 +7,10 @@ PHP NEWS
77
checks). (timwolla)
88
. The __sleep() and __wakeup() magic methods have been deprecated. (Girgias)
99

10+
- Opcache:
11+
. Fixed bug GH-19669 (assertion failure in zend_jit_trace_type_to_info_ex).
12+
(Arnaud)
13+
1014
- URI:
1115
. Fixed bug GH-19780 (InvalidUrlException should check $errors argument).
1216
(nielsdos)

ext/opcache/jit/zend_jit_ir.c

Lines changed: 12 additions & 15 deletions
Original file line numberDiff line numberDiff line change
@@ -4808,33 +4808,30 @@ static int zend_jit_inc_dec(zend_jit_ctx *jit, const zend_op *opline, uint32_t o
48084808
int32_t exit_point;
48094809
const void *exit_addr;
48104810
zend_jit_trace_stack *stack;
4811-
uint32_t old_res_info = 0;
4811+
uint32_t old_res_info = 0, old_op1_info = 0;
48124812

48134813
stack = JIT_G(current_frame)->stack;
48144814
if (opline->result_type != IS_UNUSED) {
48154815
old_res_info = STACK_INFO(stack, EX_VAR_TO_NUM(opline->result.var));
4816+
SET_STACK_TYPE(stack, EX_VAR_TO_NUM(opline->result.var), IS_LONG, 0);
48164817
if (opline->opcode == ZEND_PRE_INC || opline->opcode == ZEND_PRE_DEC) {
4817-
SET_STACK_TYPE(stack, EX_VAR_TO_NUM(opline->result.var), IS_LONG, 0);
4818+
SET_STACK_REF(stack, EX_VAR_TO_NUM(opline->result.var), ref);
4819+
} else {
4820+
SET_STACK_REF(stack, EX_VAR_TO_NUM(opline->result.var), op1_lval_ref);
48184821
}
48194822
}
4823+
old_op1_info = STACK_INFO(stack, EX_VAR_TO_NUM(opline->op1.var));
4824+
SET_STACK_TYPE(stack, EX_VAR_TO_NUM(opline->op1.var), IS_LONG, 0);
4825+
SET_STACK_REF(stack, EX_VAR_TO_NUM(opline->op1.var), ref);
4826+
48204827
exit_point = zend_jit_trace_get_exit_point(opline + 1, 0);
48214828
exit_addr = zend_jit_trace_get_exit_addr(exit_point);
4822-
if ((opline->opcode == ZEND_PRE_INC || opline->opcode == ZEND_PRE_DEC) &&
4823-
opline->result_type != IS_UNUSED) {
4824-
if_overflow = ir_IF(ir_OVERFLOW(ref));
4825-
ir_IF_FALSE_cold(if_overflow);
4826-
jit_set_Z_LVAL(jit, res_addr, ref);
4827-
if (Z_MODE(res_addr) != IS_REG) {
4828-
jit_set_Z_TYPE_INFO(jit, res_addr, IS_LONG);
4829-
}
4830-
jit_SIDE_EXIT(jit, ir_CONST_ADDR(exit_addr));
4831-
ir_IF_TRUE(if_overflow);
4832-
} else {
4833-
ir_GUARD(ir_OVERFLOW(ref), ir_CONST_ADDR(exit_addr));
4834-
}
4829+
ir_GUARD(ir_OVERFLOW(ref), ir_CONST_ADDR(exit_addr));
4830+
48354831
if (opline->result_type != IS_UNUSED) {
48364832
SET_STACK_INFO(stack, EX_VAR_TO_NUM(opline->result.var), old_res_info);
48374833
}
4834+
SET_STACK_INFO(stack, EX_VAR_TO_NUM(opline->op1.var), old_op1_info);
48384835
} else {
48394836
if_overflow = ir_IF(ir_OVERFLOW(ref));
48404837
ir_IF_FALSE(if_overflow);
Lines changed: 24 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,24 @@
1+
--TEST--
2+
GH-19669: assertion failure zend_jit_trace_type_to_info_ex
3+
--CREDITS--
4+
YuanchengJiang
5+
--SKIPIF--
6+
<?php
7+
if (PHP_INT_SIZE !== 8) {
8+
die('skip output depends PHP_INT_SIZE=8');
9+
}
10+
?>
11+
--FILE--
12+
<?php
13+
function test() {
14+
$a = PHP_INT_MIN;
15+
$b = 0;
16+
while ($b++ < 2) {
17+
$a = (int) ($a-- + $a - $b);
18+
}
19+
return $a;
20+
}
21+
var_dump(test());
22+
?>
23+
--EXPECT--
24+
int(-3)
Lines changed: 24 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,24 @@
1+
--TEST--
2+
GH-19669 002: assertion failure zend_jit_trace_type_to_info_ex
3+
--CREDITS--
4+
YuanchengJiang
5+
--SKIPIF--
6+
<?php
7+
if (PHP_INT_SIZE !== 8) {
8+
die('skip output depends PHP_INT_SIZE=8');
9+
}
10+
?>
11+
--FILE--
12+
<?php
13+
function test() {
14+
$a = PHP_INT_MIN;
15+
$b = -1;
16+
while ($b++ < 2) {
17+
$a = (int) (--$a + $a - $b);
18+
}
19+
return $a;
20+
}
21+
var_dump(test());
22+
?>
23+
--EXPECT--
24+
int(-10)

0 commit comments

Comments
 (0)