@@ -418,6 +418,8 @@ def __repr__(self) -> str:
418418 data .append (f"startdepth={ self .startdepth } " )
419419 if self .next :
420420 data .append (f"next={ self .next .bid } " )
421+ if self .is_exc_handler :
422+ data .append ("EH" )
421423 extras = ", " .join (data )
422424 if self .label :
423425 return f"<block { self .label } { extras } >"
@@ -2356,6 +2358,103 @@ def flatten_jump(self, inst: Instruction, pc: int) -> int:
23562358
23572359 return res
23582360
2361+ def mark_except_handlers (self ) -> None :
2362+ for block in self .ordered_blocks :
2363+ for instr in block .insts :
2364+ if instr .opname in SETUP_OPCODES :
2365+ target = instr .target
2366+ assert target is not None , "SETUP_* opcodes all have targets"
2367+ target .is_exc_handler = True
2368+ break
2369+
2370+ def push_cold_blocks_to_end (
2371+ self , except_handlers : set [Block ] | None , optimizer : FlowGraphOptimizer
2372+ ) -> None :
2373+ warm = self .compute_warm ()
2374+ cold = self .compute_cold (warm )
2375+
2376+ # If we have a cold block with fallthrough to a warm block, add
2377+ # an explicit jump instead of fallthrough
2378+ for block in list (self .ordered_blocks ):
2379+ if block in cold and block .has_fallthrough and block .next in warm :
2380+ explicit_jump = self .make_explicit_jump_block ()
2381+ explicit_jump .bid = self .get_new_block_id ()
2382+ explicit_jump .num_predecessors = 1
2383+ cold .add (explicit_jump )
2384+ self .current = explicit_jump
2385+
2386+ next_block = block .next
2387+ assert next_block is not None
2388+
2389+ self .emit_jump_forward_noline (next_block )
2390+ self .ordered_blocks .insert (
2391+ self .ordered_blocks .index (block ) + 1 , explicit_jump
2392+ )
2393+
2394+ explicit_jump .next = block .next
2395+ explicit_jump .has_fallthrough = False
2396+ block .next = explicit_jump
2397+
2398+ new_ordered = []
2399+ to_end = []
2400+ prev = None
2401+ for block in self .ordered_blocks :
2402+ if block in warm :
2403+ new_ordered .append (block )
2404+ if prev is not None :
2405+ prev .next = block
2406+ block .prev = prev
2407+ prev = block
2408+ else :
2409+ to_end .append (block )
2410+
2411+ for block in to_end :
2412+ prev .next = block
2413+ block .prev = prev
2414+ prev = block
2415+
2416+ block .next = None
2417+
2418+ self .ordered_blocks = new_ordered + to_end
2419+ if to_end :
2420+ self .remove_redundant_nops_and_jumps (optimizer )
2421+
2422+ def has_fallthrough (self , block : Block ) -> bool :
2423+ if not block .insts :
2424+ return True
2425+
2426+ last = block .insts [- 1 ]
2427+ return (
2428+ last .opname not in UNCONDITIONAL_JUMP_OPCODES
2429+ and last .opname not in SCOPE_EXIT_OPCODES
2430+ )
2431+
2432+ def compute_cold (self , warm : set [Block ]) -> set [Block ]:
2433+ stack = []
2434+ cold = set ()
2435+ visited = set ()
2436+
2437+ for block in self .ordered_blocks :
2438+ if block .is_exc_handler :
2439+ assert block not in warm
2440+ stack .append (block )
2441+
2442+ for block in stack :
2443+ cold .add (block )
2444+ next = block .next
2445+ if next is not None and self .has_fallthrough (block ):
2446+ if next not in warm and next not in visited :
2447+ stack .append (next )
2448+ visited .add (next )
2449+
2450+ for instr in block .insts :
2451+ if instr .is_jump (self .opcode ):
2452+ target = instr .target
2453+ if target not in warm and target not in visited :
2454+ stack .append (target )
2455+ visited .add (target )
2456+ return cold
2457+
23592458 # The following bits are chosen so that the value of
23602459 # COMPARSION_BIT(left, right)
23612460 # masked by the values below will be non-zero if the
@@ -3025,7 +3124,7 @@ def remove_redundant_nops_and_jumps(self, optimizer: FlowGraphOptimizer) -> None
30253124
30263125 def optimizeCFG (self ) -> None :
30273126 """Optimize a well-formed CFG."""
3028- except_handlers = self .compute_except_handlers ()
3127+ self .mark_except_handlers ()
30293128
30303129 self .label_exception_targets ()
30313130
@@ -3059,7 +3158,7 @@ def optimizeCFG(self) -> None:
30593158 self .remove_unused_consts ()
30603159 self .add_checks_for_loads_of_uninitialized_variables ()
30613160 self .insert_superinstructions ()
3062- self .push_cold_blocks_to_end (except_handlers , optimizer )
3161+ self .push_cold_blocks_to_end (None , optimizer )
30633162 self .propagate_line_numbers ()
30643163
30653164 _const_opcodes : set [str ] = set (PyFlowGraph312 ._const_opcodes ) | {"LOAD_SMALL_INT" }
0 commit comments