Skip to content

Lay out exception handling code at end of code unit #93356

Closed
@iritkatriel

Description

@iritkatriel

We would like try-except to run fastest when no exception is raised ('the happy path'). Currently the code is laid out such that in the happy path we need to jump over the except block (see faster-cpython/ideas#226).

We can avoid this jump if we place the except block at the end of the function's bytecode block. To do this, the compiler will detect "cold" basic blocks (those only reachable from exception targets) and reorder the blocks so that the cold blocks are at the end.

Example:

def f():
   try:
     x = "try"
   except:
     x = "except"
   finally:
     x = "finally"
     return x

Becomes:

    1           0 RESUME                   0

  2           2 NOP

  3           4 LOAD_CONST               1 ('try')
              6 STORE_FAST               0 (x)

  7     >>    8 LOAD_CONST               3 ('finally')
             10 STORE_FAST               0 (x)

  8          12 LOAD_FAST                0 (x)
             14 RETURN_VALUE
        >>   16 PUSH_EXC_INFO

  4          18 POP_TOP

  5          20 LOAD_CONST               2 ('except')
             22 STORE_FAST               0 (x)
             24 POP_EXCEPT
             26 JUMP_BACKWARD           10 (to 8)
        >>   28 COPY                     3
             30 POP_EXCEPT
             32 RERAISE                  1
        >>   34 PUSH_EXC_INFO

  7          36 LOAD_CONST               3 ('finally')
             38 STORE_FAST               0 (x)

  8          40 LOAD_FAST                0 (x)
             42 SWAP                     2
             44 POP_TOP
             46 SWAP                     2
             48 POP_EXCEPT
             50 RETURN_VALUE
        >>   52 COPY                     3
             54 POP_EXCEPT
             56 RERAISE                  1
ExceptionTable:
  4 to 6 -> 16 [0]
  16 to 22 -> 28 [1] lasti
  24 to 32 -> 34 [0]
  34 to 46 -> 52 [1] lasti

instead of:

   1           0 RESUME                   0

  2           2 NOP

  3           4 LOAD_CONST               1 ('try')
              6 STORE_FAST               0 (x)
              8 JUMP_FORWARD             9 (to 28)    <--  this jump was removed
        >>   10 PUSH_EXC_INFO

  4          12 POP_TOP

  5          14 LOAD_CONST               2 ('except')
             16 STORE_FAST               0 (x)
             18 POP_EXCEPT
             20 JUMP_FORWARD             3 (to 28)
        >>   22 COPY                     3
             24 POP_EXCEPT
             26 RERAISE                  1

  7     >>   28 LOAD_CONST               3 ('finally')
             30 STORE_FAST               0 (x)

  8          32 LOAD_FAST                0 (x)
             34 RETURN_VALUE
        >>   36 PUSH_EXC_INFO

  7          38 LOAD_CONST               3 ('finally')
             40 STORE_FAST               0 (x)

  8          42 LOAD_FAST                0 (x)
             44 SWAP                     2
             46 POP_TOP
             48 SWAP                     2
             50 POP_EXCEPT
             52 RETURN_VALUE
        >>   54 COPY                     3
             56 POP_EXCEPT
             58 RERAISE                  1
ExceptionTable:
  4 to 6 -> 10 [0]
  8 to 8 -> 36 [0]
  10 to 16 -> 22 [1] lasti
  18 to 26 -> 36 [0]
  36 to 48 -> 54 [1] lasti

Metadata

Metadata

Assignees

No one assigned

    Labels

    type-featureA feature request or enhancement

    Projects

    No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions