@@ -246,8 +246,6 @@ get_oparg(PyObject *self, PyObject *Py_UNUSED(ignored))
246246///////////////////// Experimental UOp Optimizer /////////////////////
247247
248248static int executor_clear (PyObject * executor );
249- static void unlink_executor (_PyExecutorObject * executor );
250-
251249
252250void
253251_PyExecutor_Free (_PyExecutorObject * self )
@@ -258,63 +256,76 @@ _PyExecutor_Free(_PyExecutorObject *self)
258256 PyObject_GC_Del (self );
259257}
260258
259+ static void executor_invalidate (PyObject * op );
260+
261+ static void
262+ executor_clear_exits (_PyExecutorObject * executor )
263+ {
264+ _PyExecutorObject * cold = _PyExecutor_GetColdExecutor ();
265+ _PyExecutorObject * cold_dynamic = _PyExecutor_GetColdDynamicExecutor ();
266+ for (uint32_t i = 0 ; i < executor -> exit_count ; i ++ ) {
267+ _PyExitData * exit = & executor -> exits [i ];
268+ exit -> temperature = initial_unreachable_backoff_counter ();
269+ _PyExecutorObject * old = executor -> exits [i ].executor ;
270+ exit -> executor = exit -> is_dynamic ? cold_dynamic : cold ;
271+ Py_DECREF (old );
272+ }
273+ }
274+
275+
261276void
262277_Py_ClearExecutorDeletionList (PyInterpreterState * interp )
263278{
279+ if (interp -> executor_deletion_list_head == NULL ) {
280+ return ;
281+ }
264282 _PyRuntimeState * runtime = & _PyRuntime ;
265283 HEAD_LOCK (runtime );
266284 PyThreadState * ts = PyInterpreterState_ThreadHead (interp );
285+ while (ts ) {
286+ _PyExecutorObject * current = (_PyExecutorObject * )ts -> current_executor ;
287+ Py_XINCREF (current );
288+ ts = ts -> next ;
289+ }
267290 HEAD_UNLOCK (runtime );
291+ _PyExecutorObject * keep_list = NULL ;
292+ do {
293+ _PyExecutorObject * exec = interp -> executor_deletion_list_head ;
294+ interp -> executor_deletion_list_head = exec -> vm_data .links .next ;
295+ if (Py_REFCNT (exec ) == 0 ) {
296+ _PyExecutor_Free (exec );
297+ } else {
298+ exec -> vm_data .links .next = keep_list ;
299+ keep_list = exec ;
300+ }
301+ } while (interp -> executor_deletion_list_head != NULL );
302+ interp -> executor_deletion_list_head = keep_list ;
303+ HEAD_LOCK (runtime );
304+ ts = PyInterpreterState_ThreadHead (interp );
268305 while (ts ) {
269306 _PyExecutorObject * current = (_PyExecutorObject * )ts -> current_executor ;
270307 if (current != NULL ) {
271- /* Anything in this list will be unlinked, so we can reuse the
272- * linked field as a reachability marker. */
273- current -> vm_data .linked = 1 ;
308+ _Py_DECREF_NO_DEALLOC ((PyObject * )current );
274309 }
275- HEAD_LOCK (runtime );
276- ts = PyThreadState_Next (ts );
277- HEAD_UNLOCK (runtime );
278- }
279- _PyExecutorObject * * prev_to_next_ptr = & interp -> executor_deletion_list_head ;
280- _PyExecutorObject * exec = * prev_to_next_ptr ;
281- while (exec != NULL ) {
282- if (exec -> vm_data .linked ) {
283- // This executor is currently executing
284- exec -> vm_data .linked = 0 ;
285- prev_to_next_ptr = & exec -> vm_data .links .next ;
286- }
287- else {
288- * prev_to_next_ptr = exec -> vm_data .links .next ;
289- _PyExecutor_Free (exec );
290- }
291- exec = * prev_to_next_ptr ;
310+ ts = ts -> next ;
292311 }
293- interp -> executor_deletion_list_remaining_capacity = EXECUTOR_DELETE_LIST_MAX ;
312+ HEAD_UNLOCK ( runtime ) ;
294313}
295314
296315static void
297316add_to_pending_deletion_list (_PyExecutorObject * self )
298317{
299318 PyInterpreterState * interp = PyInterpreterState_Get ();
319+ self -> vm_data .links .previous = NULL ;
300320 self -> vm_data .links .next = interp -> executor_deletion_list_head ;
301321 interp -> executor_deletion_list_head = self ;
302- if (interp -> executor_deletion_list_remaining_capacity > 0 ) {
303- interp -> executor_deletion_list_remaining_capacity -- ;
304- }
305- else {
306- _Py_ClearExecutorDeletionList (interp );
307- }
308322}
309323
310324static void
311325uop_dealloc (PyObject * op ) {
312326 _PyExecutorObject * self = _PyExecutorObject_CAST (op );
313- _PyObject_GC_UNTRACK ( self );
327+ executor_invalidate ( op );
314328 assert (self -> vm_data .code == NULL );
315- unlink_executor (self );
316- // Once unlinked it becomes impossible to invalidate an executor, so do it here.
317- self -> vm_data .valid = 0 ;
318329 add_to_pending_deletion_list (self );
319330}
320331
@@ -1621,19 +1632,14 @@ link_executor(_PyExecutorObject *executor)
16211632 head -> vm_data .links .previous = executor ;
16221633 interp -> executor_list_head = executor ;
16231634 }
1624- executor -> vm_data .linked = true;
16251635 /* executor_list_head must be first in list */
16261636 assert (interp -> executor_list_head -> vm_data .links .previous == NULL );
16271637}
16281638
16291639static void
16301640unlink_executor (_PyExecutorObject * executor )
16311641{
1632- if (!executor -> vm_data .linked ) {
1633- return ;
1634- }
16351642 _PyExecutorLinkListNode * links = & executor -> vm_data .links ;
1636- assert (executor -> vm_data .valid );
16371643 _PyExecutorObject * next = links -> next ;
16381644 _PyExecutorObject * prev = links -> previous ;
16391645 if (next != NULL ) {
@@ -1648,7 +1654,6 @@ unlink_executor(_PyExecutorObject *executor)
16481654 assert (interp -> executor_list_head == executor );
16491655 interp -> executor_list_head = next ;
16501656 }
1651- executor -> vm_data .linked = false;
16521657}
16531658
16541659/* This must be called by optimizers before using the executor */
@@ -1662,61 +1667,47 @@ _Py_ExecutorInit(_PyExecutorObject *executor, const _PyBloomFilter *dependency_s
16621667 link_executor (executor );
16631668}
16641669
1665- _PyExecutorObject *
1666- _PyExecutor_GetColdExecutor ( void )
1670+ static _PyExecutorObject *
1671+ make_cold_executor ( uint16_t opcode )
16671672{
1668- PyInterpreterState * interp = _PyInterpreterState_GET ();
1669- if (interp -> cold_executor != NULL ) {
1670- return interp -> cold_executor ;
1671- }
16721673 _PyExecutorObject * cold = allocate_executor (0 , 1 );
16731674 if (cold == NULL ) {
16741675 Py_FatalError ("Cannot allocate core JIT code" );
16751676 }
1676- ((_PyUOpInstruction * )cold -> trace )-> opcode = _COLD_EXIT_r00 ;
1677- #ifdef _Py_JIT
1678- cold -> jit_code = NULL ;
1679- cold -> jit_size = 0 ;
1677+ ((_PyUOpInstruction * )cold -> trace )-> opcode = opcode ;
16801678 // This is initialized to true so we can prevent the executor
16811679 // from being immediately detected as cold and invalidated.
16821680 cold -> vm_data .warm = true;
1681+ #ifdef _Py_JIT
1682+ cold -> jit_code = NULL ;
1683+ cold -> jit_size = 0 ;
16831684 if (_PyJIT_Compile (cold , cold -> trace , 1 )) {
16841685 Py_DECREF (cold );
16851686 Py_FatalError ("Cannot allocate core JIT code" );
16861687 }
16871688#endif
16881689 _Py_SetImmortal ((PyObject * )cold );
1689- interp -> cold_executor = cold ;
16901690 return cold ;
16911691}
16921692
16931693_PyExecutorObject *
1694- _PyExecutor_GetColdDynamicExecutor (void )
1694+ _PyExecutor_GetColdExecutor (void )
16951695{
16961696 PyInterpreterState * interp = _PyInterpreterState_GET ();
1697- if (interp -> cold_dynamic_executor != NULL ) {
1698- assert (interp -> cold_dynamic_executor -> trace [0 ].opcode == _COLD_DYNAMIC_EXIT_r00 );
1699- return interp -> cold_dynamic_executor ;
1700- }
1701- _PyExecutorObject * cold = allocate_executor (0 , 1 );
1702- if (cold == NULL ) {
1703- Py_FatalError ("Cannot allocate core JIT code" );
1697+ if (interp -> cold_executor == NULL ) {
1698+ return interp -> cold_executor = make_cold_executor (_COLD_EXIT_r00 );;
17041699 }
1705- ((_PyUOpInstruction * )cold -> trace )-> opcode = _COLD_DYNAMIC_EXIT_r00 ;
1706- #ifdef _Py_JIT
1707- cold -> jit_code = NULL ;
1708- cold -> jit_size = 0 ;
1709- // This is initialized to true so we can prevent the executor
1710- // from being immediately detected as cold and invalidated.
1711- cold -> vm_data .warm = true;
1712- if (_PyJIT_Compile (cold , cold -> trace , 1 )) {
1713- Py_DECREF (cold );
1714- Py_FatalError ("Cannot allocate core JIT code" );
1700+ return interp -> cold_executor ;
1701+ }
1702+
1703+ _PyExecutorObject *
1704+ _PyExecutor_GetColdDynamicExecutor (void )
1705+ {
1706+ PyInterpreterState * interp = _PyInterpreterState_GET ();
1707+ if (interp -> cold_dynamic_executor == NULL ) {
1708+ interp -> cold_dynamic_executor = make_cold_executor (_COLD_DYNAMIC_EXIT_r00 );
17151709 }
1716- #endif
1717- _Py_SetImmortal ((PyObject * )cold );
1718- interp -> cold_dynamic_executor = cold ;
1719- return cold ;
1710+ return interp -> cold_dynamic_executor ;
17201711}
17211712
17221713void
@@ -1755,32 +1746,28 @@ _Py_ExecutorDetach(_PyExecutorObject *executor)
17551746 Py_DECREF (executor );
17561747}
17571748
1758- static int
1759- executor_clear (PyObject * op )
1749+ /* Executors can be invalidated at any time,
1750+ even with a stop-the-world lock held.
1751+ Consequently it must not run arbitrary code,
1752+ including Py_DECREF with a non-executor. */
1753+ static void
1754+ executor_invalidate (PyObject * op )
17601755{
17611756 _PyExecutorObject * executor = _PyExecutorObject_CAST (op );
17621757 if (!executor -> vm_data .valid ) {
1763- return 0 ;
1758+ return ;
17641759 }
1765- assert (executor -> vm_data .valid == 1 );
1766- unlink_executor (executor );
17671760 executor -> vm_data .valid = 0 ;
1768-
1769- /* It is possible for an executor to form a reference
1770- * cycle with itself, so decref'ing a side exit could
1771- * free the executor unless we hold a strong reference to it
1772- */
1773- _PyExecutorObject * cold = _PyExecutor_GetColdExecutor ();
1774- Py_INCREF (executor );
1775- for (uint32_t i = 0 ; i < executor -> exit_count ; i ++ ) {
1776- executor -> exits [i ].temperature = initial_unreachable_backoff_counter ();
1777- _PyExecutorObject * e = executor -> exits [i ].executor ;
1778- executor -> exits [i ].executor = cold ;
1779- Py_DECREF (e );
1780- }
1761+ unlink_executor (executor );
1762+ executor_clear_exits (executor );
17811763 _Py_ExecutorDetach (executor );
1782- Py_DECREF (executor );
1783- return 0 ;
1764+ _PyObject_GC_UNTRACK (op );
1765+ }
1766+
1767+ static int
1768+ executor_clear (PyObject * op )
1769+ {
1770+ executor_invalidate (op );
17841771}
17851772
17861773void
@@ -1805,7 +1792,7 @@ _Py_Executors_InvalidateDependency(PyInterpreterState *interp, void *obj, int is
18051792 if (invalidate == NULL ) {
18061793 goto error ;
18071794 }
1808- /* Clearing an executor can deallocate others, so we need to make a list of
1795+ /* Clearing an executor can clear others, so we need to make a list of
18091796 * executors to invalidate first */
18101797 for (_PyExecutorObject * exec = interp -> executor_list_head ; exec != NULL ;) {
18111798 assert (exec -> vm_data .valid );
@@ -1819,7 +1806,7 @@ _Py_Executors_InvalidateDependency(PyInterpreterState *interp, void *obj, int is
18191806 }
18201807 for (Py_ssize_t i = 0 ; i < PyList_GET_SIZE (invalidate ); i ++ ) {
18211808 PyObject * exec = PyList_GET_ITEM (invalidate , i );
1822- executor_clear (exec );
1809+ executor_invalidate (exec );
18231810 if (is_invalidation ) {
18241811 OPT_STAT_INC (executors_invalidated );
18251812 }
@@ -1851,13 +1838,13 @@ _Py_Executors_InvalidateAll(PyInterpreterState *interp, int is_invalidation)
18511838{
18521839 while (interp -> executor_list_head ) {
18531840 _PyExecutorObject * executor = interp -> executor_list_head ;
1854- assert (executor -> vm_data .valid == 1 && executor -> vm_data . linked == 1 );
1841+ assert (executor -> vm_data .valid );
18551842 if (executor -> vm_data .code ) {
18561843 // Clear the entire code object so its co_executors array be freed:
18571844 _PyCode_Clear_Executors (executor -> vm_data .code );
18581845 }
18591846 else {
1860- executor_clear ((PyObject * )executor );
1847+ executor_invalidate ((PyObject * )executor );
18611848 }
18621849 if (is_invalidation ) {
18631850 OPT_STAT_INC (executors_invalidated );
@@ -1892,7 +1879,7 @@ _Py_Executors_InvalidateCold(PyInterpreterState *interp)
18921879 }
18931880 for (Py_ssize_t i = 0 ; i < PyList_GET_SIZE (invalidate ); i ++ ) {
18941881 PyObject * exec = PyList_GET_ITEM (invalidate , i );
1895- executor_clear (exec );
1882+ executor_invalidate (exec );
18961883 }
18971884 Py_DECREF (invalidate );
18981885 return ;
0 commit comments