Skip to content

Commit 368dd81

Browse files
committed
Merge branch 'PHP-8.1' into PHP-8.2
* PHP-8.1: Fix incorrect match default branch optimization
2 parents 8318f4a + 3a76f79 commit 368dd81

File tree

3 files changed

+49
-10
lines changed

3 files changed

+49
-10
lines changed

NEWS

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -2,6 +2,8 @@ PHP NEWS
22
|||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
33
?? ??? ????, PHP 8.2.7
44

5+
- Opcache:
6+
. Fixed bug GH-11134 (Incorrect match default branch optimization). (ilutov)
57

68
11 May 2023, PHP 8.2.6
79

Zend/Optimizer/dfa_pass.c

Lines changed: 19 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -938,32 +938,41 @@ static int zend_dfa_optimize_jmps(zend_op_array *op_array, zend_ssa *ssa)
938938
|| (opline->opcode == ZEND_SWITCH_STRING && type == IS_STRING)
939939
|| (opline->opcode == ZEND_MATCH && (type == IS_LONG || type == IS_STRING));
940940

941-
if (!correct_type) {
941+
/* Switch statements have a fallback chain for loose comparison. In those
942+
* cases the SWITCH_* instruction is a NOP. Match does strict comparison and
943+
* thus jumps to the default branch on mismatched types, so we need to
944+
* convert MATCH to a jmp. */
945+
if (!correct_type && opline->opcode != ZEND_MATCH) {
942946
removed_ops++;
943947
MAKE_NOP(opline);
944948
opline->extended_value = 0;
945949
take_successor_ex(ssa, block_num, block, block->successors[block->successors_count - 1]);
946950
goto optimize_nop;
947-
} else {
951+
}
952+
953+
uint32_t target;
954+
if (correct_type) {
948955
HashTable *jmptable = Z_ARRVAL_P(CT_CONSTANT_EX(op_array, opline->op2.constant));
949956
zval *jmp_zv = type == IS_LONG
950957
? zend_hash_index_find(jmptable, Z_LVAL_P(zv))
951958
: zend_hash_find(jmptable, Z_STR_P(zv));
952959

953-
uint32_t target;
954960
if (jmp_zv) {
955961
target = ZEND_OFFSET_TO_OPLINE_NUM(op_array, opline, Z_LVAL_P(jmp_zv));
956962
} else {
957963
target = ZEND_OFFSET_TO_OPLINE_NUM(op_array, opline, opline->extended_value);
958964
}
959-
opline->opcode = ZEND_JMP;
960-
opline->extended_value = 0;
961-
SET_UNUSED(opline->op1);
962-
ZEND_SET_OP_JMP_ADDR(opline, opline->op1, op_array->opcodes + target);
963-
SET_UNUSED(opline->op2);
964-
take_successor_ex(ssa, block_num, block, ssa->cfg.map[target]);
965-
goto optimize_jmp;
965+
} else {
966+
ZEND_ASSERT(opline->opcode == ZEND_MATCH);
967+
target = ZEND_OFFSET_TO_OPLINE_NUM(op_array, opline, opline->extended_value);
966968
}
969+
opline->opcode = ZEND_JMP;
970+
opline->extended_value = 0;
971+
SET_UNUSED(opline->op1);
972+
ZEND_SET_OP_JMP_ADDR(opline, opline->op1, op_array->opcodes + target);
973+
SET_UNUSED(opline->op2);
974+
take_successor_ex(ssa, block_num, block, ssa->cfg.map[target]);
975+
goto optimize_jmp;
967976
}
968977
break;
969978
case ZEND_NOP:

Zend/tests/match/gh11134.phpt

Lines changed: 28 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,28 @@
1+
--TEST--
2+
GH-11134: Incorrect match optimization
3+
--FILE--
4+
<?php
5+
6+
function testMatch() {
7+
return match ($unset ?? null) {
8+
'foo' => 'foo',
9+
'bar' => 'bar',
10+
default => 'baz',
11+
};
12+
}
13+
14+
function testSwitch() {
15+
switch ($unset ?? null) {
16+
case 'foo': return 'foo';
17+
case 'bar': return 'bar';
18+
default: return 'baz';
19+
}
20+
}
21+
22+
var_dump(testMatch());
23+
var_dump(testSwitch());
24+
25+
?>
26+
--EXPECT--
27+
string(3) "baz"
28+
string(3) "baz"

0 commit comments

Comments
 (0)