@@ -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
@@ -1619,19 +1630,14 @@ link_executor(_PyExecutorObject *executor)
16191630 head -> vm_data .links .previous = executor ;
16201631 interp -> executor_list_head = executor ;
16211632 }
1622- executor -> vm_data .linked = true;
16231633 /* executor_list_head must be first in list */
16241634 assert (interp -> executor_list_head -> vm_data .links .previous == NULL );
16251635}
16261636
16271637static void
16281638unlink_executor (_PyExecutorObject * executor )
16291639{
1630- if (!executor -> vm_data .linked ) {
1631- return ;
1632- }
16331640 _PyExecutorLinkListNode * links = & executor -> vm_data .links ;
1634- assert (executor -> vm_data .valid );
16351641 _PyExecutorObject * next = links -> next ;
16361642 _PyExecutorObject * prev = links -> previous ;
16371643 if (next != NULL ) {
@@ -1646,7 +1652,6 @@ unlink_executor(_PyExecutorObject *executor)
16461652 assert (interp -> executor_list_head == executor );
16471653 interp -> executor_list_head = next ;
16481654 }
1649- executor -> vm_data .linked = false;
16501655}
16511656
16521657/* This must be called by optimizers before using the executor */
@@ -1660,61 +1665,47 @@ _Py_ExecutorInit(_PyExecutorObject *executor, const _PyBloomFilter *dependency_s
16601665 link_executor (executor );
16611666}
16621667
1663- _PyExecutorObject *
1664- _PyExecutor_GetColdExecutor ( void )
1668+ static _PyExecutorObject *
1669+ make_cold_executor ( uint16_t opcode )
16651670{
1666- PyInterpreterState * interp = _PyInterpreterState_GET ();
1667- if (interp -> cold_executor != NULL ) {
1668- return interp -> cold_executor ;
1669- }
16701671 _PyExecutorObject * cold = allocate_executor (0 , 1 );
16711672 if (cold == NULL ) {
16721673 Py_FatalError ("Cannot allocate core JIT code" );
16731674 }
1674- ((_PyUOpInstruction * )cold -> trace )-> opcode = _COLD_EXIT_r00 ;
1675- #ifdef _Py_JIT
1676- cold -> jit_code = NULL ;
1677- cold -> jit_size = 0 ;
1675+ ((_PyUOpInstruction * )cold -> trace )-> opcode = opcode ;
16781676 // This is initialized to true so we can prevent the executor
16791677 // from being immediately detected as cold and invalidated.
16801678 cold -> vm_data .warm = true;
1679+ #ifdef _Py_JIT
1680+ cold -> jit_code = NULL ;
1681+ cold -> jit_size = 0 ;
16811682 if (_PyJIT_Compile (cold , cold -> trace , 1 )) {
16821683 Py_DECREF (cold );
16831684 Py_FatalError ("Cannot allocate core JIT code" );
16841685 }
16851686#endif
16861687 _Py_SetImmortal ((PyObject * )cold );
1687- interp -> cold_executor = cold ;
16881688 return cold ;
16891689}
16901690
16911691_PyExecutorObject *
1692- _PyExecutor_GetColdDynamicExecutor (void )
1692+ _PyExecutor_GetColdExecutor (void )
16931693{
16941694 PyInterpreterState * interp = _PyInterpreterState_GET ();
1695- if (interp -> cold_dynamic_executor != NULL ) {
1696- assert (interp -> cold_dynamic_executor -> trace [0 ].opcode == _COLD_DYNAMIC_EXIT_r00 );
1697- return interp -> cold_dynamic_executor ;
1698- }
1699- _PyExecutorObject * cold = allocate_executor (0 , 1 );
1700- if (cold == NULL ) {
1701- Py_FatalError ("Cannot allocate core JIT code" );
1695+ if (interp -> cold_executor == NULL ) {
1696+ return interp -> cold_executor = make_cold_executor (_COLD_EXIT_r00 );;
17021697 }
1703- ((_PyUOpInstruction * )cold -> trace )-> opcode = _COLD_DYNAMIC_EXIT_r00 ;
1704- #ifdef _Py_JIT
1705- cold -> jit_code = NULL ;
1706- cold -> jit_size = 0 ;
1707- // This is initialized to true so we can prevent the executor
1708- // from being immediately detected as cold and invalidated.
1709- cold -> vm_data .warm = true;
1710- if (_PyJIT_Compile (cold , cold -> trace , 1 )) {
1711- Py_DECREF (cold );
1712- Py_FatalError ("Cannot allocate core JIT code" );
1698+ return interp -> cold_executor ;
1699+ }
1700+
1701+ _PyExecutorObject *
1702+ _PyExecutor_GetColdDynamicExecutor (void )
1703+ {
1704+ PyInterpreterState * interp = _PyInterpreterState_GET ();
1705+ if (interp -> cold_dynamic_executor == NULL ) {
1706+ interp -> cold_dynamic_executor = make_cold_executor (_COLD_DYNAMIC_EXIT_r00 );
17131707 }
1714- #endif
1715- _Py_SetImmortal ((PyObject * )cold );
1716- interp -> cold_dynamic_executor = cold ;
1717- return cold ;
1708+ return interp -> cold_dynamic_executor ;
17181709}
17191710
17201711void
@@ -1753,32 +1744,28 @@ _Py_ExecutorDetach(_PyExecutorObject *executor)
17531744 Py_DECREF (executor );
17541745}
17551746
1756- static int
1757- executor_clear (PyObject * op )
1747+ /* Executors can be invalidated at any time,
1748+ even with a stop-the-world lock held.
1749+ Consequently it must not run arbitrary code,
1750+ including Py_DECREF with a non-executor. */
1751+ static void
1752+ executor_invalidate (PyObject * op )
17581753{
17591754 _PyExecutorObject * executor = _PyExecutorObject_CAST (op );
17601755 if (!executor -> vm_data .valid ) {
1761- return 0 ;
1756+ return ;
17621757 }
1763- assert (executor -> vm_data .valid == 1 );
1764- unlink_executor (executor );
17651758 executor -> vm_data .valid = 0 ;
1766-
1767- /* It is possible for an executor to form a reference
1768- * cycle with itself, so decref'ing a side exit could
1769- * free the executor unless we hold a strong reference to it
1770- */
1771- _PyExecutorObject * cold = _PyExecutor_GetColdExecutor ();
1772- Py_INCREF (executor );
1773- for (uint32_t i = 0 ; i < executor -> exit_count ; i ++ ) {
1774- executor -> exits [i ].temperature = initial_unreachable_backoff_counter ();
1775- _PyExecutorObject * e = executor -> exits [i ].executor ;
1776- executor -> exits [i ].executor = cold ;
1777- Py_DECREF (e );
1778- }
1759+ unlink_executor (executor );
1760+ executor_clear_exits (executor );
17791761 _Py_ExecutorDetach (executor );
1780- Py_DECREF (executor );
1781- return 0 ;
1762+ _PyObject_GC_UNTRACK (op );
1763+ }
1764+
1765+ static int
1766+ executor_clear (PyObject * op )
1767+ {
1768+ executor_invalidate (op );
17821769}
17831770
17841771void
@@ -1803,7 +1790,7 @@ _Py_Executors_InvalidateDependency(PyInterpreterState *interp, void *obj, int is
18031790 if (invalidate == NULL ) {
18041791 goto error ;
18051792 }
1806- /* Clearing an executor can deallocate others, so we need to make a list of
1793+ /* Clearing an executor can clear others, so we need to make a list of
18071794 * executors to invalidate first */
18081795 for (_PyExecutorObject * exec = interp -> executor_list_head ; exec != NULL ;) {
18091796 assert (exec -> vm_data .valid );
@@ -1817,7 +1804,7 @@ _Py_Executors_InvalidateDependency(PyInterpreterState *interp, void *obj, int is
18171804 }
18181805 for (Py_ssize_t i = 0 ; i < PyList_GET_SIZE (invalidate ); i ++ ) {
18191806 PyObject * exec = PyList_GET_ITEM (invalidate , i );
1820- executor_clear (exec );
1807+ executor_invalidate (exec );
18211808 if (is_invalidation ) {
18221809 OPT_STAT_INC (executors_invalidated );
18231810 }
@@ -1849,13 +1836,13 @@ _Py_Executors_InvalidateAll(PyInterpreterState *interp, int is_invalidation)
18491836{
18501837 while (interp -> executor_list_head ) {
18511838 _PyExecutorObject * executor = interp -> executor_list_head ;
1852- assert (executor -> vm_data .valid == 1 && executor -> vm_data . linked == 1 );
1839+ assert (executor -> vm_data .valid );
18531840 if (executor -> vm_data .code ) {
18541841 // Clear the entire code object so its co_executors array be freed:
18551842 _PyCode_Clear_Executors (executor -> vm_data .code );
18561843 }
18571844 else {
1858- executor_clear ((PyObject * )executor );
1845+ executor_invalidate ((PyObject * )executor );
18591846 }
18601847 if (is_invalidation ) {
18611848 OPT_STAT_INC (executors_invalidated );
@@ -1890,7 +1877,7 @@ _Py_Executors_InvalidateCold(PyInterpreterState *interp)
18901877 }
18911878 for (Py_ssize_t i = 0 ; i < PyList_GET_SIZE (invalidate ); i ++ ) {
18921879 PyObject * exec = PyList_GET_ITEM (invalidate , i );
1893- executor_clear (exec );
1880+ executor_invalidate (exec );
18941881 }
18951882 Py_DECREF (invalidate );
18961883 return ;
0 commit comments