-
Notifications
You must be signed in to change notification settings - Fork 7.8k
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
assertion failure spl_fixedarray #18274
Comments
This feels like a VM problem to me. The point is that after getting the zval pointer for the dimension CV or the value CV, we don't check for an exception. So that means the dimension handlers are executed regardless of there being an exception, and then the assertion in SplFixedArray fails of course. That also means that the following code: <?php
set_error_handler(fn ($_,$str) => throw new Error($str));
$b = [];
try {
$b[0] = $a;
} catch(Error $e) {
echo $e->getMessage(), "\n";
}
var_dump($b); results in
despite the access to |
Interestingly the following snippet works as expected ( set_error_handler(fn ($_,$str) => throw new Error($str));
$b = new class implements ArrayAccess {
function offsetSet($name, $value): void {
var_dump($name, $value);
}
function offsetGet($value): mixed {
var_dump($value);
}
function offsetExists($name): bool {
return true;
}
function offsetUnset($name): void {
}
};
$b[0] = $a; However this doesn't feel right. I agree the VM should check for exceptions here, after calling Possibly we have the same issue for The right long term fix is probably #12805. IMHO we should delay error handlers until the next interrupt check, just like signals and timeouts. |
I think this is the default behavior for pretty much all handlers. E.g.
I think this will be the wrong solution again once we promote access on undeclared variables to errors. |
I just realized this won't work well either, because we very often need to clean up on exit, e.g. I'm not sure yet what the best approach is. |
We could move the undefined check to a separate opcode, emit the opcode when a CV is accessed, and rely on the optimizer to remove the unnecessary ones (when we can determine that a CV is always defined before a use). This may have a performance impact, but if most uses can be determined to be defined, this may be positive. |
@Girgias got this idea before and talked to me about that briefly. I was skeptical because it's an extra dispatch and handler overhead. If the optimizer can eliminate most of them then this can be positive indeed, but I don't know. Anyway, I'm leaning towards just fixing this in SPL (by refactoring the code in such a way we don't need the exception assertion as an optimization hint anyway). |
This should indeed work well with opcache. I wonder if we can have very simple liveliness tracking during compilation to avoid a penalty without opcache. This shouldn't be too hard. |
I would imagine that any function body would be able to elide them at compile time, as it seems very unlikely that an undefined variable is used in such a body. The annoying thing for global variables is that it is possible to unset them via |
Main functions will need special care in general due to access to globals in error handlers. They can probably compile to FETCH_R instead if we want to drop the check from all other handlers. |
master...iluuu1994:php-src:undeclared-var-error I'm working on a patch. It's a simple implementation that re-uses the existing |
Although it would be great if somebody else could run my patch, because I'm seeing weird performance behavior on my machine again. Forcefully eliding all |
I checked out your patch, and there's missed optimization opportunities for CHECK_VAR, and a few things that will be hard to further improve. First, if you run Zend/bench.php and dump the opcodes you'll see for Secondly, I'm not going to even run Symfony, just the built-in benchmarks already show a significant slowdown. e.g. ~0.251 after your patch vs ~0.221 before on Zend/bench.php. Also a noticeable difference on Zend/micro_bench.php, although less severe. |
I didn't check bench.php yet. Can you see improvements when commenting the following line? I can verify your finding. The auto-vivification itself is not the problem, but the loop isn't guaranteed to execute, hence creating a phi-node for the undef $X and one for the $X created in the loop, which prevents elimination of CHECK_VAR. Even hard-coding the $n to 10 doesn't fix this, so loops that are guaranteed to run is something the optimizer currently doesn't seem to understand. Tbf, I think this is not idiomatic code nowadays. Usually the variable will be before the loop and populated in the loop. Still, would be nice if we could support this. |
While the question whether or not the loop executes is part of the problem, what I said is also a problem. Take a look at
~0.212 now instead of ~0.221, so an improvement of ~4.1%.
This is often hard to prove in real code. |
Testing with the emit commented out, I don't see a performance difference on Symfony demo between stock PHP and your patch. |
Ah, yes indeed. I have already started refactoring For the second loop in
That is... less promising. I would have expected at least something, given so many paths are affected, not just in terms of instructions executed but also instruction cache pressure. |
I get -0.35% instruction count under valgrind with
This seems promising to me :) Edit: didn't see #18274 (comment), but -4% on bench.php is still nice and can make some difference on real code. Plus it simplifies op code handlers.
Unroll their first iteration may be a good way to improve both loops. |
Description
The following code:
Resulted in this output:
To reproduce:
Commit:
Configurations:
Operating System:
This report is automatically generated by FlowFusion
PHP Version
ac9392b
Operating System
No response
The text was updated successfully, but these errors were encountered: