Re: Discussion: making continue and break into an expression

From: Date: Thu, 25 Jan 2024 18:08:17 +0000
Subject: Re: Discussion: making continue and break into an expression
References: 1 2 3  Groups: php.internals 
Request: Send a blank email to internals+get-122258@lists.php.net to get a copy of this message
Hi Larry On Thu, Jan 25, 2024 at 6:38 PM Larry Garfield <larry@garfieldtech.com> wrote: > > On Thu, Jan 25, 2024, at 11:28 AM, Ilija Tovilo wrote: > > > > This leads to very similar issues as break/continue inside blocks. See: > > > > https://wiki.php.net/rfc/match_blocks#technical_implications_of_control_statements > > > I'm curious, how did throw expressions manage to avoid > these issues? Or was it just "Ilija did the hard work of tracking down the weirdness?" Can't really take the credit for this. This issue went over my head, as this was my first RFC. Exceptions work a bit differently, in that they use something called live-ranges. Essentially, we look at the generated opcodes and figure out which variables are "live" (i.e. valid and unfreed) during which opcodes. For something like echo foo() + bar(): Pseudo opcodes: 0000 V1 = CALL foo 0001 V2 = CALL bar 0003 V3 = ADD V1 V2 0004 ECHO V3 V1 would be live for 0000-0003, V2 for 0001-0003, V3 for 0003-0004. If an exception is thrown (or rethrown across function boundaries) the VM checks which temporary variables are currently live and frees them. So if CALL bar were to throw, we'd see that V1 is currently live and needs to be freed. For something like foo() + throw new Exception(), if you replace the second CALL with a throw, you'll see that the live-range for V1 doesn't change, and so this "just works". There was, however, a related issue with the optimizer. echo foo() + throw new Exception(); 0000 V1 = CALL foo 0001 THROW 0003 V3 = ADD V1 false 0004 ECHO V3 Where the optimizer would remove the dead instructions after the throw, breaking live-range analysis. 0000 V1 = CALL foo 0001 THROW V1 no longer had a consuming opcode, and as such the algorithm could no longer determine the live-range of V1. This would cause V1 to leak. The solution was simply to disable dead code elimination for this case. The solution was suggested by Tyson Andre and implemented by Nikita. In theory, break/continue expressions might try to re-use live-ranges. I recall thinking about this, but I can't seem to remember if there was a reason not to do it. Ilija

« previous php.internals (#122258) next »