Strange disassembly

Chris Angelico rosuav at gmail.com
Sat Jun 19 03:53:11 EDT 2021


On Sat, Jun 19, 2021 at 5:13 PM Rob Cliffe via Python-list
<python-list at python.org> wrote:
>
>
>
> On 19/06/2021 07:50, Chris Angelico wrote:
> > On Sat, Jun 19, 2021 at 4:16 PM Rob Cliffe via Python-list
> > <python-list at python.org> wrote:
> >>
> >>
> >> On 18/06/2021 11:04, Chris Angelico wrote:
> >>>>>> sys.version
> >>> '3.10.0b2+ (heads/3.10:33a7a24288, Jun  9 2021, 20:47:39) [GCC 8.3.0]'
> >>>>>> def chk(x):
> >>> ...     if not(0 < x < 10): raise Exception
> >>> ...
> >>>>>> dis.dis(chk)
> >>>     2           0 LOAD_CONST               1 (0)
> >>>                 2 LOAD_FAST                0 (x)
> >>>                 4 DUP_TOP
> >>>                 6 ROT_THREE
> >>>                 8 COMPARE_OP               0 (<)
> >>>                10 POP_JUMP_IF_FALSE       11 (to 22)
> >>>                12 LOAD_CONST               2 (10)
> >>>                14 COMPARE_OP               0 (<)
> >>>                16 POP_JUMP_IF_TRUE        14 (to 28)
> >>>                18 LOAD_GLOBAL              0 (Exception)
> >>>                20 RAISE_VARARGS            1
> >>>           >>   22 POP_TOP
> >>>                24 LOAD_GLOBAL              0 (Exception)
> >>>                26 RAISE_VARARGS            1
> >>>           >>   28 LOAD_CONST               0 (None)
> >>>                30 RETURN_VALUE
> >>> Why are there two separate bytecode blocks for the "raise Exception"?
> >>> 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.
> >>>
> >>> ChrisA
> >> As an ornery human I could refactor this to avoid the code duplication as
> >>
> >>     2           0 LOAD_CONST               1 (0)
> >>                 2 LOAD_FAST                0 (x)
> >>                 4 DUP_TOP
> >>                 6 ROT_THREE
> >>                 8 COMPARE_OP               0 (<)
> >>                10 POP_JUMP_IF_TRUE        10 (to 18)
> >>                12 POP_TOP
> >>           >>   14 LOAD_GLOBAL              0 (Exception)
> >>                16 RAISE_VARARGS            1
> >>           >>   18 LOAD_CONST               2 (10)
> >>                20 COMPARE_OP               0 (<)
> >>                22 POP_JUMP_IF_FALSE       21 (to 14)
> >>                24 LOAD_CONST               0 (None)
> >>                26 RETURN_VALUE
> >>   >>>
> >>
> >> (there may be mistakes in this) but this is probably too much to expect
> >> of the compiler.
> > Hmm, I think that depends too much on knowing that the raise won't
> > return. That might be a neat optimization (effectively a form of dead
> > code removal), but otherwise, the best you could do would be to also
> > have it jump out after the raise.
> >
> > ChrisA
> Er, doesn't your original dis output make the same assumption?
> Otherwise, after this line
>
>                20 RAISE_VARARGS            1
>
> it would attempt to do an extra pop, then raise a second time.

In my original, I expected to see a single RAISE, with a jump over the
POP. The thing that surprised me was duplicating the RAISE to avoid
the jump. Either way, the behaviour would be the same, though.

ChrisA


More information about the Python-list mailing list