On 6/18/2021 8:13 PM, Chris Angelico wrote:
On Sat, Jun 19, 2021 at 9:50 AM Terry Reedy <[email protected]> wrote:
Why are there two separate bytecode blocks for the "raise Exception"?
Because one block must POP_TOP and other must not.
I'd have thought that the double condition would still be evaluated as
one thing, or at least that the jump destinations for both the
early-abort and the main evaluation should be the same.
To reuse the exception block with POP_TOP, could jump over it after the
2nd compare.
Hmm, fair enough I guess. The compiler figured that it'd be faster to
duplicate the executable code rather than have the jump.
I would not assume that any alternative was considered.
It made for a
somewhat confusing disassembly, but I presume it's faster to run.
For the simplest and fasted bytecode, write normal logic and let x be
reloaded instead of duplicated and rotated.
>>> import dis
>>> def f(x):
... if x <= 0 or 10 <= x: raise Exception
...
...
>>> dis.dis(f)
2 0 LOAD_FAST 0 (x)
2 LOAD_CONST 1 (0)
4 COMPARE_OP 1 (<=)
6 POP_JUMP_IF_TRUE 8 (to 16)
8 LOAD_CONST 2 (10)
10 LOAD_FAST 0 (x)
12 COMPARE_OP 1 (<=)
14 POP_JUMP_IF_FALSE 10 (to 20)
>> 16 LOAD_GLOBAL 0 (Exception)
18 RAISE_VARARGS 1
>> 20 LOAD_CONST 0 (None)
22 RETURN_VALUE
>>>
Makes sense. I'm not sure if this would actually run faster, but I
can't really justify warping my code around the disassembly :)
Thanks for the explanation. I guess I just assumed the interpreter
would prefer a jump to the duplication, but that's a decision it's
free to take!
--
Terry Jan Reedy
--
https://mail.python.org/mailman/listinfo/python-list