diff options
author | Nikita Popov <nikita.ppv@gmail.com> | 2020-11-09 17:06:41 +0100 |
---|---|---|
committer | Nikita Popov <nikita.ppv@gmail.com> | 2020-11-09 17:08:16 +0100 |
commit | d971b67027c69390cb1fc2243eca1e3901401bf6 (patch) | |
tree | e77da621c6a0d0a18c3c156bee19506f1a24ba76 | |
parent | 96b725122daad0a7d9abe8aad4d14787f8dc15e9 (diff) | |
download | php-git-d971b67027c69390cb1fc2243eca1e3901401bf6.tar.gz |
Fix phi use chain management when renaming variable
If there is a previous use of the new variable in the phi, we need
to NULL out the use chain of the new source we're adding.
Test case is reduced from an assertion failure in the Symfony Demo.
-rw-r--r-- | ext/opcache/Optimizer/ssa_integrity.c | 16 | ||||
-rw-r--r-- | ext/opcache/Optimizer/zend_ssa.c | 8 | ||||
-rw-r--r-- | ext/opcache/tests/phi_use_chain.phpt | 19 |
3 files changed, 35 insertions, 8 deletions
diff --git a/ext/opcache/Optimizer/ssa_integrity.c b/ext/opcache/Optimizer/ssa_integrity.c index ede40be59a..9d815b7888 100644 --- a/ext/opcache/Optimizer/ssa_integrity.c +++ b/ext/opcache/Optimizer/ssa_integrity.c @@ -287,8 +287,9 @@ int ssa_verify_integrity(zend_op_array *op_array, zend_ssa *ssa, const char *ext /* Phis */ FOREACH_PHI(phi) { - int source; - FOREACH_PHI_SOURCE(phi, source) { + unsigned num_sources = NUM_PHI_SOURCES(phi); + for (i = 0; i < num_sources; i++) { + int source = phi->sources[i]; if (source < 0) { FAIL(VARFMT " negative source\n", VAR(phi->ssa_var)); } @@ -298,7 +299,16 @@ int ssa_verify_integrity(zend_op_array *op_array, zend_ssa *ssa, const char *ext if (ssa->vars[source].var != ssa->vars[phi->ssa_var].var) { FAIL(VARFMT " source of phi for " VARFMT "\n", VAR(source), VAR(phi->ssa_var)); } - } FOREACH_PHI_SOURCE_END(); + if (phi->use_chains[i]) { + int j; + for (j = i + 1; j < num_sources; j++) { + if (phi->sources[j] == source && phi->use_chains[j]) { + FAIL("use chain for source " VARFMT " of phi " VARFMT + " at %d despite earlier use\n", VAR(source), VAR(phi->ssa_var), j); + } + } + } + } if (ssa->vars[phi->ssa_var].definition_phi != phi) { FAIL(VARFMT " does not define this phi\n", VAR(phi->ssa_var)); } diff --git a/ext/opcache/Optimizer/zend_ssa.c b/ext/opcache/Optimizer/zend_ssa.c index 89dfe57914..0b8c76d3ac 100644 --- a/ext/opcache/Optimizer/zend_ssa.c +++ b/ext/opcache/Optimizer/zend_ssa.c @@ -1298,11 +1298,7 @@ static inline void zend_ssa_remove_phi_source(zend_ssa *ssa, zend_ssa_phi *phi, for (j = 0; j < predecessors_count; j++) { if (phi->sources[j] == var_num) { if (j < pred_offset) { - if (next_phi == NULL) { - next_phi = phi->use_chains[pred_offset]; - } else { - ZEND_ASSERT(phi->use_chains[pred_offset] == NULL); - } + ZEND_ASSERT(next_phi == NULL); } else if (j >= pred_offset) { phi->use_chains[j] = next_phi; } @@ -1591,6 +1587,8 @@ void zend_ssa_rename_var_uses(zend_ssa *ssa, int old, int new, zend_bool update_ new_var->phi_use_chain = phi; } after_first_new_source = 1; + } else { + phi->use_chains[j] = NULL; } } } diff --git a/ext/opcache/tests/phi_use_chain.phpt b/ext/opcache/tests/phi_use_chain.phpt new file mode 100644 index 0000000000..173d874d21 --- /dev/null +++ b/ext/opcache/tests/phi_use_chain.phpt @@ -0,0 +1,19 @@ +--TEST-- +Check that phi use chains are correctly maintained when removing blocks +--FILE-- +<?php + +function test(array $adapters) { + foreach ($adapters as $adapter) { + if (\in_array('cli-server', ['cli', 'phpdbg'], true) && $adapter instanceof stdClass && !\filter_var('1', \FILTER_VALIDATE_BOOLEAN)) { + continue; + } + + $adapters[] = $adapter; + } +} + +?> +===DONE=== +--EXPECT-- +===DONE=== |