@@ -860,6 +860,7 @@ _PyJit_translate_single_bytecode_to_trace(
860860 if (uop == _PUSH_FRAME || uop == _RETURN_VALUE || uop == _RETURN_GENERATOR || uop == _YIELD_VALUE ) {
861861 PyCodeObject * new_code = (PyCodeObject * )PyStackRef_AsPyObjectBorrow (frame -> f_executable );
862862 PyFunctionObject * new_func = (PyFunctionObject * )PyStackRef_AsPyObjectBorrow (frame -> f_funcobj );
863+
863864 if (new_func != NULL ) {
864865 operand = (uintptr_t )new_func ;
865866 DPRINTF (2 , "Adding %p func to op\n" , (void * )operand );
@@ -1277,7 +1278,17 @@ uop_optimize(
12771278 _PyExecutorObject * * exec_ptr ,
12781279 bool progress_needed )
12791280{
1280- _PyBloomFilter * dependencies = & tstate -> interp -> jit_state .dependencies ;
1281+ // Note: the executor has a slightly different set of dependencies than the tracer.
1282+ // For example: the tracer depends on function and code objects.
1283+ // The executor may only depend on the code object.
1284+ // Furthermore, it may decide to cut the trace early, meaning it does not depend on the rest
1285+ // of the code objects in the trace.
1286+ // It is crucial we differentiate them for performance reasons.
1287+ // This prevents endless re-tracing for nested functions.
1288+ // It is the optimizer's responsibility to add the dependencies it requires on its own.
1289+ _PyBloomFilter new_dependencies ;
1290+ _Py_BloomFilter_Init (& new_dependencies );
1291+ _Py_BloomFilter_Add (& new_dependencies , tstate -> interp -> jit_state .initial_code );
12811292 PyInterpreterState * interp = _PyInterpreterState_GET ();
12821293 _PyUOpInstruction * buffer = interp -> jit_state .code_buffer ;
12831294 OPT_STAT_INC (attempts );
@@ -1298,7 +1309,7 @@ uop_optimize(
12981309 if (!is_noopt ) {
12991310 length = _Py_uop_analyze_and_optimize (tstate -> interp -> jit_state .initial_func , buffer ,
13001311 length ,
1301- curr_stackentries , dependencies );
1312+ curr_stackentries , & new_dependencies );
13021313 if (length <= 0 ) {
13031314 return length ;
13041315 }
@@ -1321,7 +1332,7 @@ uop_optimize(
13211332 OPT_HIST (effective_trace_length (buffer , length ), optimized_trace_length_hist );
13221333 length = prepare_for_execution (buffer , length );
13231334 assert (length <= UOP_MAX_TRACE_LENGTH );
1324- _PyExecutorObject * executor = make_executor_from_uops (buffer , length , dependencies , tstate -> interp -> jit_state .initial_chain_depth );
1335+ _PyExecutorObject * executor = make_executor_from_uops (buffer , length , & new_dependencies , tstate -> interp -> jit_state .initial_chain_depth );
13251336 if (executor == NULL ) {
13261337 return -1 ;
13271338 }
0 commit comments