@@ -2708,7 +2708,7 @@ load_fast_push_block(basicblock ***sp, basicblock *target,
27082708/*
27092709 * Recursively determine if a borrowed reference remains safe along all CFG paths.
27102710 *
2711- * This function performs a Depth-First Search ( DFS) starting from 'current_block'.
2711+ * This function performs a DFS starting from 'current_block'.
27122712 * It tracks a specific value that was notionally loaded by a LOAD_FAST_BORROW
27132713 * instruction and is currently at 'depth_of_value_on_entry' on the operand stack
27142714 * (0 being TOS, -1 if already known to be consumed). The 'original_local_idx'
@@ -2733,20 +2733,11 @@ load_fast_push_block(basicblock ***sp, basicblock *target,
27332733 * - 'depth_of_value_on_entry': The depth of the tracked item upon entering 'current_block'.
27342734 * - 'current_target_depth': The depth of the item as instructions in 'current_block' are processed.
27352735 * - 'depth_before_jump_op_effect': When a jump instruction is encountered, this
2736- * is calculated by simulating all prior instructions in 'current_block' to find
2737- * the item's depth *just before* the jump instruction itself has any stack effect.
2738- * This precise depth is then used to calculate the 'target_entry_depth' for the
2739- * recursive call to the jump's target block.
2736+ * is calculated by simulating all prior instructions in 'current_block' to find
2737+ * the item's depth *just before* the jump instruction itself has any stack effect.
2738+ * This precise depth is then used to calculate the 'target_entry_depth' for the
2739+ * recursive call to the jump's target block.
27402740 *
2741- * Args:
2742- * current_block: The basic block to start analysis from for this recursive step.
2743- * depth_of_value_on_entry: The depth of the tracked borrowed value from TOS
2744- * (0 = TOS, -1 if already consumed).
2745- * original_local_idx: The index of the local variable backing the borrow.
2746- * g: The CFG builder.
2747- *
2748- * Returns:
2749- * true if the borrow is safe along all paths from this point, false otherwise.
27502741 */
27512742static bool
27522743is_borrow_safe (
@@ -2771,40 +2762,34 @@ is_borrow_safe(
27712762 int opcode = instr -> i_opcode ;
27722763 int oparg = instr -> i_oparg ;
27732764
2774- // 1. Check if the original local is killed before the value is consumed.
27752765 if ((opcode == STORE_FAST || opcode == DELETE_FAST || opcode == LOAD_FAST_AND_CLEAR ) &&
27762766 oparg == original_local_idx ) {
27772767 return false;
27782768 }
27792769
2780- // 2. Simulate stack effect and check for consumption or unsafe store.
27812770 stack_effects effects_noj ;
27822771 if (get_stack_effects (opcode , oparg , 0 , & effects_noj ) < 0 ) {
2783- return false; // Error in stack effect calculation
2772+ return false;
27842773 }
27852774 int num_popped = _PyOpcode_num_popped (opcode , oparg );
27862775 int num_pushed = _PyOpcode_num_pushed (opcode , oparg );
27872776
27882777 if (current_target_depth < num_popped ) {
27892778 if (opcode == STORE_FAST && current_target_depth == 0 ) {
2790- // Unsafe: borrowed value was at TOS and is being stored into a local.
27912779 return false;
27922780 }
2793- return true; // Safely consumed by this instruction.
2781+ return true;
27942782 }
2795- // Value not consumed, update its depth.
27962783 current_target_depth = current_target_depth - num_popped + num_pushed ;
27972784
2798- // 3. Handle branches (jumps are always last in a basic block).
27992785 if (HAS_TARGET (opcode )) {
28002786 if (i != current_block -> b_iused - 1 ) {
28012787 continue ; // Skip jumps that are not the last instruction in the block.
28022788 }
28032789 bool safe_on_all_branches = true;
28042790
2805- // Calculate item's depth just before this jump instruction's own stack effect.
28062791 Py_ssize_t depth_before_jump_op_effect = depth_of_value_on_entry ;
2807- for (int k = 0 ; k < i ; ++ k ) { // Iterate instructions before the current jump
2792+ for (int k = 0 ; k < i ; ++ k ) {
28082793 cfg_instr * prev_instr_in_block = & current_block -> b_instr [k ];
28092794 // Kill check for intermediate instructions
28102795 if ((prev_instr_in_block -> i_opcode == STORE_FAST ||
@@ -2818,11 +2803,11 @@ is_borrow_safe(
28182803 return false;
28192804 }
28202805 int prev_popped_val = _PyOpcode_num_popped (prev_instr_in_block -> i_opcode , prev_instr_in_block -> i_oparg );
2821- if (depth_before_jump_op_effect < prev_popped_val ) { // Consumed before jump
2806+ if (depth_before_jump_op_effect < prev_popped_val ) {
28222807 if (prev_instr_in_block -> i_opcode == STORE_FAST && depth_before_jump_op_effect == 0 ) {
2823- return false; // Stored into local
2808+ return false;
28242809 }
2825- return true; // Safely consumed before the jump
2810+ return true;
28262811 }
28272812 depth_before_jump_op_effect = depth_before_jump_op_effect - prev_popped_val +
28282813 _PyOpcode_num_pushed (prev_instr_in_block -> i_opcode , prev_instr_in_block -> i_oparg );
@@ -2834,11 +2819,10 @@ is_borrow_safe(
28342819 int jump_popped_val = _PyOpcode_num_popped (opcode , oparg );
28352820 Py_ssize_t target_entry_depth = depth_before_jump_op_effect ;
28362821
2837- if (target_entry_depth < jump_popped_val ) { // Consumed by the jump op itself
2822+ if (target_entry_depth < jump_popped_val ) {
28382823 if (opcode == STORE_FAST && target_entry_depth == 0 ) {
28392824 safe_on_all_branches = false;
28402825 }
2841- // else: safely consumed by jump operation.
28422826 } else { // Not consumed by jump op, recurse on target.
28432827 target_entry_depth = target_entry_depth - jump_popped_val + _PyOpcode_num_pushed (opcode , oparg );
28442828 if (!is_borrow_safe (instr -> i_target , target_entry_depth , original_local_idx , g )) {
@@ -2848,7 +2832,6 @@ is_borrow_safe(
28482832
28492833 // Analyze fallthrough path for conditional jumps, if the jump path was safe.
28502834 if (safe_on_all_branches && IS_CONDITIONAL_JUMP_OPCODE (opcode ) && current_block -> b_next ) {
2851- // 'current_target_depth' already reflects the stack state if the jump is *not* taken.
28522835 if (!is_borrow_safe (current_block -> b_next , current_target_depth , original_local_idx , g )) {
28532836 safe_on_all_branches = false;
28542837 }
@@ -2862,14 +2845,16 @@ is_borrow_safe(
28622845 return is_borrow_safe (current_block -> b_next , current_target_depth , original_local_idx , g );
28632846 }
28642847
2865- // No further path (or no fallthrough) and value is still on stack (current_target_depth is valid).
2866- // This means it's unconsumed at the end of a CFG path.
2848+ /*
2849+ No further path (or no fallthrough) and value is still on stack (current_target_depth is valid).
2850+ This means it's unconsumed at the end of a CFG path, so it's unsafe.
2851+ */
28672852 return false;
28682853}
28692854
28702855
28712856/*
2872- * Initiates a Control Flow Graph ( CFG) wide safety check for a borrowed reference.
2857+ * Initiates a CFG wide safety check for a borrowed reference.
28732858 *
28742859 * This function is called when a LOAD_FAST instruction is a candidate for
28752860 * LOAD_FAST_BORROW, but its produced value ('REF_UNCONSUMED' flag is set)
@@ -2888,17 +2873,6 @@ is_borrow_safe(
28882873 * to ensure that 'is_borrow_safe()' uses a fresh set of visited markers
28892874 * ('b_dfs_visited_gen') for its analysis.
28902875 *
2891- * Args:
2892- * producer_block: The basic block containing the LOAD_FAST candidate.
2893- * depth_of_value_at_producer_end: The depth of the candidate borrowed value
2894- * from TOS at the end of 'producer_block'.
2895- * (0 = TOS, -1 if already consumed - though
2896- * this function expects a live value).
2897- * original_local_idx: The index of the local variable backing the borrow.
2898- * g: The CFG builder.
2899- *
2900- * Returns:
2901- * true if the borrow is safe across all subsequent CFG paths, false otherwise.
29022876 */
29032877static bool
29042878check_borrow_safety_globally (
@@ -2923,11 +2897,10 @@ check_borrow_safety_globally(
29232897 int jump_popped = _PyOpcode_num_popped (last_instr -> i_opcode , last_instr -> i_oparg );
29242898 Py_ssize_t entry_depth_for_target = depth_of_value_at_producer_end ;
29252899
2926- if (entry_depth_for_target < jump_popped ) { // Consumed by the jump itself.
2900+ if (entry_depth_for_target < jump_popped ) {
29272901 if (last_instr -> i_opcode == STORE_FAST && entry_depth_for_target == 0 ) {
2928- overall_safety = false; // Unsafe store of borrowed value.
2902+ overall_safety = false;
29292903 }
2930- // else: safely consumed.
29312904 } else {
29322905 entry_depth_for_target = entry_depth_for_target - jump_popped +
29332906 _PyOpcode_num_pushed (last_instr -> i_opcode , last_instr -> i_oparg );
@@ -2938,17 +2911,16 @@ check_borrow_safety_globally(
29382911
29392912 // Analyze fallthrough path for conditional jumps, if the jump path was safe.
29402913 if (overall_safety && IS_CONDITIONAL_JUMP_OPCODE (last_instr -> i_opcode ) && producer_block -> b_next ) {
2941- stack_effects effects_fall ; // Stack effect if jump is NOT taken.
2914+ stack_effects effects_fall ;
29422915 if (get_stack_effects (last_instr -> i_opcode , last_instr -> i_oparg , 0 , & effects_fall ) < 0 ) return false;
29432916 int fall_popped = _PyOpcode_num_popped (last_instr -> i_opcode , last_instr -> i_oparg );
29442917 Py_ssize_t entry_depth_for_fallthrough = depth_of_value_at_producer_end ;
29452918
2946- if (entry_depth_for_fallthrough < fall_popped ) { // Consumed by not taking jump.
2919+ if (entry_depth_for_fallthrough < fall_popped ) {
29472920 if (last_instr -> i_opcode == STORE_FAST && entry_depth_for_fallthrough == 0 ) {
2948- overall_safety = false; // Unsafe store.
2921+ overall_safety = false;
29492922 }
2950- // else: safely consumed.
2951- } else { // Not consumed by not taking jump, recurse on fallthrough.
2923+ } else { // Recurse on fallthrough.
29522924 entry_depth_for_fallthrough = entry_depth_for_fallthrough - fall_popped +
29532925 _PyOpcode_num_pushed (last_instr -> i_opcode , last_instr -> i_oparg );
29542926 if (!is_borrow_safe (producer_block -> b_next , entry_depth_for_fallthrough , original_local_idx , g )) {
@@ -2960,8 +2932,8 @@ check_borrow_safety_globally(
29602932 if (!is_borrow_safe (producer_block -> b_next , depth_of_value_at_producer_end , original_local_idx , g )) {
29612933 overall_safety = false;
29622934 }
2963- } else { // No successors (e.g., block ends in RETURN/RAISE) and value still on stack.
2964- overall_safety = false; // Unconsumed at end of a CFG path.
2935+ } else {
2936+ overall_safety = false;
29652937 }
29662938 return overall_safety ;
29672939}
0 commit comments