mirror of
https://github.com/php/php-src.git
synced 2024-09-21 18:07:23 +00:00
Fixed bug #81046
Literal compaction was incorrectly assuming that literals with the same base literal and the same number of related literals would be equal. Maybe that was the case historically, but at least it isn't true in PHP 8, where FETCH_CONSTANT and INIT_METHOD have distinct literals at the second position. Fix this by making the cache key a concatenation of all literals, rather than just the base literal. We still distinguish the number of related literals based on a bias added to the string hash.
This commit is contained in:
parent
f0736631d9
commit
c446d68f7c
2
NEWS
2
NEWS
@ -31,6 +31,8 @@ PHP NEWS
|
|||||||
(Nikita)
|
(Nikita)
|
||||||
. Fixed bug #81015 (Opcache optimization assumes wrong part of ternary
|
. Fixed bug #81015 (Opcache optimization assumes wrong part of ternary
|
||||||
operator in if-condition). (Nikita)
|
operator in if-condition). (Nikita)
|
||||||
|
. Fixed bug #81046 (Literal compaction merges non-equal related literals).
|
||||||
|
(Nikita)
|
||||||
|
|
||||||
- PDO_MySQL:
|
- PDO_MySQL:
|
||||||
. Fixed bug #81037 (PDO discards error message text from prepared
|
. Fixed bug #81037 (PDO discards error message text from prepared
|
||||||
|
@ -113,6 +113,41 @@ static uint32_t add_static_slot(HashTable *hash,
|
|||||||
return ret;
|
return ret;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
static zend_string *create_str_cache_key(zval *literal, uint32_t flags)
|
||||||
|
{
|
||||||
|
ZEND_ASSERT(Z_TYPE_P(literal) == IS_STRING);
|
||||||
|
uint32_t num_related = LITERAL_NUM_RELATED(flags);
|
||||||
|
if (num_related == 1) {
|
||||||
|
return zend_string_copy(Z_STR_P(literal));
|
||||||
|
}
|
||||||
|
if ((flags & LITERAL_KIND_MASK) == LITERAL_VALUE) {
|
||||||
|
/* Don't merge LITERAL_VALUE that has related literals */
|
||||||
|
return NULL;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* Concatenate all the related literals for the cache key. */
|
||||||
|
zend_string *key;
|
||||||
|
if (num_related == 2) {
|
||||||
|
ZEND_ASSERT(Z_TYPE_P(literal + 1) == IS_STRING);
|
||||||
|
key = zend_string_concat2(
|
||||||
|
Z_STRVAL_P(literal), Z_STRLEN_P(literal),
|
||||||
|
Z_STRVAL_P(literal + 1), Z_STRLEN_P(literal + 1));
|
||||||
|
} else if (num_related == 3) {
|
||||||
|
ZEND_ASSERT(Z_TYPE_P(literal + 1) == IS_STRING && Z_TYPE_P(literal + 2) == IS_STRING);
|
||||||
|
key = zend_string_concat3(
|
||||||
|
Z_STRVAL_P(literal), Z_STRLEN_P(literal),
|
||||||
|
Z_STRVAL_P(literal + 1), Z_STRLEN_P(literal + 1),
|
||||||
|
Z_STRVAL_P(literal + 2), Z_STRLEN_P(literal + 2));
|
||||||
|
} else {
|
||||||
|
ZEND_ASSERT(0 && "Currently not needed");
|
||||||
|
}
|
||||||
|
|
||||||
|
/* Add a bias to the hash so we can distinguish keys
|
||||||
|
* that would otherwise be the same after concatenation. */
|
||||||
|
ZSTR_H(key) = zend_string_hash_val(key) + num_related - 1;
|
||||||
|
return key;
|
||||||
|
}
|
||||||
|
|
||||||
void zend_optimizer_compact_literals(zend_op_array *op_array, zend_optimizer_ctx *ctx)
|
void zend_optimizer_compact_literals(zend_op_array *op_array, zend_optimizer_ctx *ctx)
|
||||||
{
|
{
|
||||||
zend_op *opline, *end;
|
zend_op *opline, *end;
|
||||||
@ -407,16 +442,7 @@ void zend_optimizer_compact_literals(zend_op_array *op_array, zend_optimizer_ctx
|
|||||||
}
|
}
|
||||||
break;
|
break;
|
||||||
case IS_STRING: {
|
case IS_STRING: {
|
||||||
if (LITERAL_NUM_RELATED(info[i].flags) == 1) {
|
key = create_str_cache_key(&op_array->literals[i], info[i].flags);
|
||||||
key = zend_string_copy(Z_STR(op_array->literals[i]));
|
|
||||||
} else if ((info[i].flags & LITERAL_KIND_MASK) != LITERAL_VALUE) {
|
|
||||||
key = zend_string_init(Z_STRVAL(op_array->literals[i]), Z_STRLEN(op_array->literals[i]), 0);
|
|
||||||
ZSTR_H(key) = ZSTR_HASH(Z_STR(op_array->literals[i])) +
|
|
||||||
LITERAL_NUM_RELATED(info[i].flags) - 1;
|
|
||||||
} else {
|
|
||||||
/* Don't merge LITERAL_VALUE that has related literals */
|
|
||||||
key = NULL;
|
|
||||||
}
|
|
||||||
if (key && (pos = zend_hash_find(&hash, key)) != NULL &&
|
if (key && (pos = zend_hash_find(&hash, key)) != NULL &&
|
||||||
Z_TYPE(op_array->literals[Z_LVAL_P(pos)]) == IS_STRING &&
|
Z_TYPE(op_array->literals[Z_LVAL_P(pos)]) == IS_STRING &&
|
||||||
LITERAL_NUM_RELATED(info[i].flags) == LITERAL_NUM_RELATED(info[Z_LVAL_P(pos)].flags) &&
|
LITERAL_NUM_RELATED(info[i].flags) == LITERAL_NUM_RELATED(info[Z_LVAL_P(pos)].flags) &&
|
||||||
|
19
ext/opcache/tests/bug81046.phpt
Normal file
19
ext/opcache/tests/bug81046.phpt
Normal file
@ -0,0 +1,19 @@
|
|||||||
|
--TEST--
|
||||||
|
Bug #81046: Literal compaction merges non-equal related literals
|
||||||
|
--FILE--
|
||||||
|
<?php
|
||||||
|
|
||||||
|
class Test {
|
||||||
|
static function methoD() {
|
||||||
|
echo "Method called\n";
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
const methoD = 1;
|
||||||
|
var_dump(methoD);
|
||||||
|
test::methoD();
|
||||||
|
|
||||||
|
?>
|
||||||
|
--EXPECT--
|
||||||
|
int(1)
|
||||||
|
Method called
|
Loading…
Reference in New Issue
Block a user