Strange disassembly

Chris Angelico rosuav at gmail.com
Fri Jun 18 20:13:33 EDT 2021


On Sat, Jun 19, 2021 at 9:50 AM Terry Reedy <tjreedy at udel.edu> 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. 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!

ChrisA


More information about the Python-list mailing list