mirror of
https://github.com/php/php-src.git
synced 2025-08-16 05:58:45 +02:00
Fix incorrect match default branch optimization
Fixes GH-11134 Closes GH-11135
This commit is contained in:
parent
725f136f9a
commit
3a76f795f8
3 changed files with 49 additions and 10 deletions
2
NEWS
2
NEWS
|
@ -2,6 +2,8 @@ PHP NEWS
|
||||||
|||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
|
|||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
|
||||||
?? ??? ????, PHP 8.1.20
|
?? ??? ????, PHP 8.1.20
|
||||||
|
|
||||||
|
- Opcache:
|
||||||
|
. Fixed bug GH-11134 (Incorrect match default branch optimization). (ilutov)
|
||||||
|
|
||||||
11 May 2023, PHP 8.1.19
|
11 May 2023, PHP 8.1.19
|
||||||
|
|
||||||
|
|
|
@ -1000,24 +1000,34 @@ optimize_jmpnz:
|
||||||
|| (opline->opcode == ZEND_SWITCH_STRING && type == IS_STRING)
|
|| (opline->opcode == ZEND_SWITCH_STRING && type == IS_STRING)
|
||||||
|| (opline->opcode == ZEND_MATCH && (type == IS_LONG || type == IS_STRING));
|
|| (opline->opcode == ZEND_MATCH && (type == IS_LONG || type == IS_STRING));
|
||||||
|
|
||||||
if (!correct_type) {
|
/* Switch statements have a fallback chain for loose comparison. In those
|
||||||
|
* cases the SWITCH_* instruction is a NOP. Match does strict comparison and
|
||||||
|
* thus jumps to the default branch on mismatched types, so we need to
|
||||||
|
* convert MATCH to a jmp. */
|
||||||
|
if (!correct_type && opline->opcode != ZEND_MATCH) {
|
||||||
removed_ops++;
|
removed_ops++;
|
||||||
MAKE_NOP(opline);
|
MAKE_NOP(opline);
|
||||||
opline->extended_value = 0;
|
opline->extended_value = 0;
|
||||||
take_successor_ex(ssa, block_num, block, block->successors[block->successors_count - 1]);
|
take_successor_ex(ssa, block_num, block, block->successors[block->successors_count - 1]);
|
||||||
goto optimize_nop;
|
goto optimize_nop;
|
||||||
} else {
|
}
|
||||||
|
|
||||||
|
uint32_t target;
|
||||||
|
if (correct_type) {
|
||||||
HashTable *jmptable = Z_ARRVAL_P(CT_CONSTANT_EX(op_array, opline->op2.constant));
|
HashTable *jmptable = Z_ARRVAL_P(CT_CONSTANT_EX(op_array, opline->op2.constant));
|
||||||
zval *jmp_zv = type == IS_LONG
|
zval *jmp_zv = type == IS_LONG
|
||||||
? zend_hash_index_find(jmptable, Z_LVAL_P(zv))
|
? zend_hash_index_find(jmptable, Z_LVAL_P(zv))
|
||||||
: zend_hash_find(jmptable, Z_STR_P(zv));
|
: zend_hash_find(jmptable, Z_STR_P(zv));
|
||||||
|
|
||||||
uint32_t target;
|
|
||||||
if (jmp_zv) {
|
if (jmp_zv) {
|
||||||
target = ZEND_OFFSET_TO_OPLINE_NUM(op_array, opline, Z_LVAL_P(jmp_zv));
|
target = ZEND_OFFSET_TO_OPLINE_NUM(op_array, opline, Z_LVAL_P(jmp_zv));
|
||||||
} else {
|
} else {
|
||||||
target = ZEND_OFFSET_TO_OPLINE_NUM(op_array, opline, opline->extended_value);
|
target = ZEND_OFFSET_TO_OPLINE_NUM(op_array, opline, opline->extended_value);
|
||||||
}
|
}
|
||||||
|
} else {
|
||||||
|
ZEND_ASSERT(opline->opcode == ZEND_MATCH);
|
||||||
|
target = ZEND_OFFSET_TO_OPLINE_NUM(op_array, opline, opline->extended_value);
|
||||||
|
}
|
||||||
opline->opcode = ZEND_JMP;
|
opline->opcode = ZEND_JMP;
|
||||||
opline->extended_value = 0;
|
opline->extended_value = 0;
|
||||||
SET_UNUSED(opline->op1);
|
SET_UNUSED(opline->op1);
|
||||||
|
@ -1026,7 +1036,6 @@ optimize_jmpnz:
|
||||||
take_successor_ex(ssa, block_num, block, ssa->cfg.map[target]);
|
take_successor_ex(ssa, block_num, block, ssa->cfg.map[target]);
|
||||||
goto optimize_jmp;
|
goto optimize_jmp;
|
||||||
}
|
}
|
||||||
}
|
|
||||||
break;
|
break;
|
||||||
case ZEND_NOP:
|
case ZEND_NOP:
|
||||||
optimize_nop:
|
optimize_nop:
|
||||||
|
|
28
Zend/tests/match/gh11134.phpt
Normal file
28
Zend/tests/match/gh11134.phpt
Normal file
|
@ -0,0 +1,28 @@
|
||||||
|
--TEST--
|
||||||
|
GH-11134: Incorrect match optimization
|
||||||
|
--FILE--
|
||||||
|
<?php
|
||||||
|
|
||||||
|
function testMatch() {
|
||||||
|
return match ($unset ?? null) {
|
||||||
|
'foo' => 'foo',
|
||||||
|
'bar' => 'bar',
|
||||||
|
default => 'baz',
|
||||||
|
};
|
||||||
|
}
|
||||||
|
|
||||||
|
function testSwitch() {
|
||||||
|
switch ($unset ?? null) {
|
||||||
|
case 'foo': return 'foo';
|
||||||
|
case 'bar': return 'bar';
|
||||||
|
default: return 'baz';
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
var_dump(testMatch());
|
||||||
|
var_dump(testSwitch());
|
||||||
|
|
||||||
|
?>
|
||||||
|
--EXPECT--
|
||||||
|
string(3) "baz"
|
||||||
|
string(3) "baz"
|
Loading…
Add table
Add a link
Reference in a new issue