Skip to content

Commit 3da5f99

Browse files
committed
Fix incorrect sccp optimization of zend_switch with strict comparison
1 parent 296cc4b commit 3da5f99

File tree

4 files changed

+79
-0
lines changed

4 files changed

+79
-0
lines changed

Zend/tests/match/018.phpt

Lines changed: 57 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,57 @@
1+
--TEST--
2+
Test match jump table optimizer
3+
--INI--
4+
opcache.enable=1
5+
opcache.enable_cli=1
6+
opcache.opt_debug_level=0x20000
7+
--SKIPIF--
8+
<?php if (!extension_loaded('Zend OPcache')) die('skip Zend OPcache extension not available'); ?>
9+
--FILE--
10+
<?php
11+
12+
function test() {
13+
$x = 20;
14+
match($x) {
15+
1, 2, 3, 4, 5 => { throw new RuntimeException(); },
16+
default => { echo "No match\n"; },
17+
}
18+
}
19+
test();
20+
21+
function test2() {
22+
$x = 'foo';
23+
match($x) {
24+
'1', '2', '3', '4', '5' => { throw new RuntimeException(); },
25+
default => { echo "No match\n"; },
26+
}
27+
}
28+
test2();
29+
30+
--EXPECTF--
31+
$_main:
32+
; (lines=5, args=0, vars=0, tmps=0)
33+
; (after optimizer)
34+
; %s
35+
0000 INIT_FCALL 0 %d string("test")
36+
0001 DO_UCALL
37+
0002 INIT_FCALL 0 %d string("test2")
38+
0003 DO_UCALL
39+
0004 RETURN int(1)
40+
41+
test:
42+
; (lines=2, args=0, vars=0, tmps=0)
43+
; (after optimizer)
44+
; %s
45+
0000 ECHO string("No match
46+
")
47+
0001 RETURN null
48+
49+
test2:
50+
; (lines=2, args=0, vars=0, tmps=0)
51+
; (after optimizer)
52+
; %s
53+
0000 ECHO string("No match
54+
")
55+
0001 RETURN null
56+
No match
57+
No match

Zend/zend_compile.c

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -5251,6 +5251,7 @@ void zend_compile_match(znode *result, zend_ast *ast) /* {{{ */
52515251
zend_op *opline = zend_emit_op(NULL,
52525252
jumptable_type == IS_LONG ? ZEND_SWITCH_LONG : ZEND_SWITCH_STRING,
52535253
&expr_node, &jumptable_op);
5254+
opline->extended_value = ZEND_SWITCH_STRICT_COMPARISON;
52545255
if (opline->op1_type == IS_CONST) {
52555256
Z_TRY_ADDREF_P(CT_CONSTANT(opline->op1));
52565257
}

Zend/zend_compile.h

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1027,6 +1027,9 @@ static zend_always_inline int zend_check_arg_send_type(const zend_function *zf,
10271027
#define ZEND_BRK 254
10281028
#define ZEND_CONT 255
10291029

1030+
/* Attribute whether ZEND_SWITCH_STRING or ZEND_SWITCH_LONG instructions use strict comparison */
1031+
#define ZEND_SWITCH_STRICT_COMPARISON 1
1032+
10301033

10311034
END_EXTERN_C()
10321035

ext/opcache/Optimizer/sccp.c

Lines changed: 18 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1975,6 +1975,8 @@ static void sccp_mark_feasible_successors(
19751975
s = zend_hash_num_elements(Z_ARR_P(op1)) != 0;
19761976
break;
19771977
case ZEND_SWITCH_LONG:
1978+
{
1979+
zend_bool strict_comparison = (opline->extended_value & ZEND_SWITCH_STRICT_COMPARISON) != 0;
19781980
if (Z_TYPE_P(op1) == IS_LONG) {
19791981
zend_op_array *op_array = scdf->op_array;
19801982
zend_ssa *ssa = scdf->ssa;
@@ -1989,10 +1991,19 @@ static void sccp_mark_feasible_successors(
19891991
}
19901992
scdf_mark_edge_feasible(scdf, block_num, target);
19911993
return;
1994+
} else if (strict_comparison) {
1995+
zend_op_array *op_array = scdf->op_array;
1996+
zend_ssa *ssa = scdf->ssa;
1997+
int target = ssa->cfg.map[ZEND_OFFSET_TO_OPLINE_NUM(op_array, opline, opline->extended_value)];
1998+
scdf_mark_edge_feasible(scdf, block_num, target);
1999+
return;
19922000
}
19932001
s = 0;
19942002
break;
2003+
}
19952004
case ZEND_SWITCH_STRING:
2005+
{
2006+
zend_bool strict_comparison = (opline->extended_value & ZEND_SWITCH_STRICT_COMPARISON) != 0;
19962007
if (Z_TYPE_P(op1) == IS_STRING) {
19972008
zend_op_array *op_array = scdf->op_array;
19982009
zend_ssa *ssa = scdf->ssa;
@@ -2007,9 +2018,16 @@ static void sccp_mark_feasible_successors(
20072018
}
20082019
scdf_mark_edge_feasible(scdf, block_num, target);
20092020
return;
2021+
} else if (strict_comparison) {
2022+
zend_op_array *op_array = scdf->op_array;
2023+
zend_ssa *ssa = scdf->ssa;
2024+
int target = ssa->cfg.map[ZEND_OFFSET_TO_OPLINE_NUM(op_array, opline, opline->extended_value)];
2025+
scdf_mark_edge_feasible(scdf, block_num, target);
2026+
return;
20102027
}
20112028
s = 0;
20122029
break;
2030+
}
20132031
default:
20142032
for (s = 0; s < block->successors_count; s++) {
20152033
scdf_mark_edge_feasible(scdf, block_num, block->successors[s]);

0 commit comments

Comments
 (0)