@@ -549,11 +549,6 @@ dynamic_exit_uop[MAX_UOP_ID + 1] = {
549549};
550550
551551
552- /* Exit quality constants for fitness-based trace termination.
553- * Higher values mean better places to stop the trace. */
554- #define EXIT_QUALITY_ENTER_EXECUTOR 500 // An executor already exists here
555- #define EXIT_QUALITY_DEFAULT 200 // Ordinary bytecode position
556- #define EXIT_QUALITY_SPECIALIZABLE 50 // Specializable instruction — avoid stopping here
557552
558553#ifdef Py_DEBUG
559554#define DPRINTF (level , ...) \
@@ -613,15 +608,16 @@ compute_branch_bias(uint16_t history)
613608/* Compute exit quality for the current trace position.
614609 * Higher values mean it's a better place to stop the trace. */
615610static inline int32_t
616- compute_exit_quality (_Py_CODEUNIT * target_instr , int opcode )
611+ compute_exit_quality (_Py_CODEUNIT * target_instr , int opcode ,
612+ const _PyOptimizationConfig * cfg )
617613{
618614 if (target_instr -> op .code == ENTER_EXECUTOR ) {
619- return EXIT_QUALITY_ENTER_EXECUTOR ;
615+ return ( int32_t ) cfg -> exit_quality_enter_executor ;
620616 }
621617 if (_PyOpcode_Caches [_PyOpcode_Deopt [opcode ]] > 0 ) {
622- return EXIT_QUALITY_SPECIALIZABLE ;
618+ return ( int32_t ) cfg -> exit_quality_specializable ;
623619 }
624- return EXIT_QUALITY_DEFAULT ;
620+ return ( int32_t ) cfg -> exit_quality_default ;
625621}
626622
627623/* Try to truncate the trace to the best recorded exit point.
@@ -674,7 +670,6 @@ update_trace_fitness(
674670 case JUMP_BACKWARD_NO_JIT :
675671 ts -> fitness -= cfg -> fitness_backward_edge ;
676672 break ;
677- /* JUMP_BACKWARD_NO_INTERRUPT: exempt from backward edge penalty (coroutines) */
678673 default :
679674 break ;
680675 }
@@ -817,15 +812,13 @@ _PyJit_translate_single_bytecode_to_trace(
817812 if (frame != tracer -> prev_state .instr_frame ) {
818813 _PyJitTracerTranslatorState * ts_depth = & tracer -> translator_state ;
819814 if (frame -> previous == tracer -> prev_state .instr_frame ) {
820- // Entered a deeper frame (function call inlined)
821815 ts_depth -> frame_depth ++ ;
822816 // Penalty scales with depth: shallow inlining is cheap,
823817 // deep inlining gets progressively more expensive.
824818 int32_t penalty = (int32_t )tstate -> interp -> opt_config .fitness_frame_entry
825819 * ts_depth -> frame_depth ;
826820 ts_depth -> fitness -= penalty ;
827821 } else if (ts_depth -> frame_depth > 0 ) {
828- // Returned to a shallower frame
829822 ts_depth -> frame_depth -- ;
830823 }
831824 }
@@ -838,7 +831,7 @@ _PyJit_translate_single_bytecode_to_trace(
838831 // prefer it over rewinding to last _SET_IP — this covers the
839832 // main unsupported path, not just the edge case.
840833 _PyJitTracerTranslatorState * ts_unsup = & tracer -> translator_state ;
841- if (ts_unsup -> best_exit_quality > EXIT_QUALITY_DEFAULT &&
834+ if (ts_unsup -> best_exit_quality > ( int32_t ) tstate -> interp -> opt_config . exit_quality_default &&
842835 try_best_exit_fallback (trace , ts_unsup , progress_needed )) {
843836 ADD_TO_TRACE (_EXIT_TRACE , 0 , 0 , ts_unsup -> best_exit_target );
844837 uop_buffer_last (trace )-> operand1 = true; // is_control_flow
@@ -876,37 +869,36 @@ _PyJit_translate_single_bytecode_to_trace(
876869 }
877870
878871 // Fitness-based trace quality check (before reserving space for this instruction)
879- {
880- _PyJitTracerTranslatorState * ts = & tracer -> translator_state ;
881- int32_t eq = compute_exit_quality (target_instr , opcode );
882-
883- // Record best exit candidate.
884- // Only record after minimum progress to avoid truncating to near-empty traces.
885- if (eq > ts -> best_exit_quality &&
886- uop_buffer_length (trace ) > CODE_SIZE_NO_PROGRESS ) {
887- ts -> best_exit_quality = eq ;
888- ts -> best_exit_buffer_pos = uop_buffer_length (trace );
889- ts -> best_exit_target = target ;
872+ _PyJitTracerTranslatorState * ts = & tracer -> translator_state ;
873+ int32_t eq = compute_exit_quality (target_instr , opcode ,
874+ & tstate -> interp -> opt_config );
875+
876+ // Record best exit candidate.
877+ // Only record after minimum progress to avoid truncating to near-empty traces.
878+ if (eq > ts -> best_exit_quality &&
879+ uop_buffer_length (trace ) > CODE_SIZE_NO_PROGRESS ) {
880+ ts -> best_exit_quality = eq ;
881+ ts -> best_exit_buffer_pos = uop_buffer_length (trace );
882+ ts -> best_exit_target = target ;
883+ }
884+
885+ // Check if fitness is depleted — should we stop the trace?
886+ if (ts -> fitness < eq &&
887+ !(progress_needed && uop_buffer_length (trace ) < CODE_SIZE_NO_PROGRESS )) {
888+ // Prefer stopping at the best recorded exit point
889+ if (try_best_exit_fallback (trace , ts , progress_needed )) {
890+ ADD_TO_TRACE (_EXIT_TRACE , 0 , 0 , ts -> best_exit_target );
891+ uop_buffer_last (trace )-> operand1 = true; // is_control_flow
890892 }
891-
892- // Check if fitness is depleted — should we stop the trace?
893- if (ts -> fitness < eq &&
894- !(progress_needed && uop_buffer_length (trace ) < CODE_SIZE_NO_PROGRESS )) {
895- // Prefer stopping at the best recorded exit point
896- if (try_best_exit_fallback (trace , ts , progress_needed )) {
897- ADD_TO_TRACE (_EXIT_TRACE , 0 , 0 , ts -> best_exit_target );
898- uop_buffer_last (trace )-> operand1 = true; // is_control_flow
899- }
900- else {
901- // No valid best exit — stop at current position
902- ADD_TO_TRACE (_EXIT_TRACE , 0 , 0 , target );
903- uop_buffer_last (trace )-> operand1 = true; // is_control_flow
904- }
905- OPT_STAT_INC (fitness_terminated_traces );
906- DPRINTF (2 , "Fitness terminated: fitness=%d < exit_quality=%d\n" ,
907- ts -> fitness , eq );
908- goto done ;
893+ else {
894+ // No valid best exit — stop at current position
895+ ADD_TO_TRACE (_EXIT_TRACE , 0 , 0 , target );
896+ uop_buffer_last (trace )-> operand1 = true; // is_control_flow
909897 }
898+ OPT_STAT_INC (fitness_terminated_traces );
899+ DPRINTF (2 , "Fitness terminated: fitness=%d < exit_quality=%d\n" ,
900+ ts -> fitness , eq );
901+ goto done ;
910902 }
911903
912904 // One for possible _DEOPT, one because _CHECK_VALIDITY itself might _DEOPT
0 commit comments