@@ -75,7 +75,7 @@ insert_executor(PyCodeObject *code, _Py_CODEUNIT *instr, int index, _PyExecutorO
7575 Py_INCREF (executor );
7676 if (instr -> op .code == ENTER_EXECUTOR ) {
7777 assert (index == instr -> op .arg );
78- _Py_ExecutorClear (code -> co_executors -> executors [index ]);
78+ _Py_ExecutorDetach (code -> co_executors -> executors [index ]);
7979 }
8080 else {
8181 assert (code -> co_executors -> size == index );
@@ -270,10 +270,14 @@ static PyMethodDef executor_methods[] = {
270270
271271///////////////////// Experimental UOp Optimizer /////////////////////
272272
273+ static int executor_clear (_PyExecutorObject * executor );
274+ static void unlink_executor (_PyExecutorObject * executor );
275+
273276static void
274277uop_dealloc (_PyExecutorObject * self ) {
275278 _PyObject_GC_UNTRACK (self );
276- _Py_ExecutorClear (self );
279+ assert (self -> vm_data .code == NULL );
280+ unlink_executor (self );
277281#ifdef _Py_JIT
278282 _PyJIT_Free (self );
279283#endif
@@ -379,13 +383,6 @@ PySequenceMethods uop_as_sequence = {
379383 .sq_item = (ssizeargfunc )uop_item ,
380384};
381385
382- static int
383- executor_clear (PyObject * o )
384- {
385- _Py_ExecutorClear ((_PyExecutorObject * )o );
386- return 0 ;
387- }
388-
389386static int
390387executor_traverse (PyObject * o , visitproc visit , void * arg )
391388{
@@ -412,7 +409,7 @@ PyTypeObject _PyUOpExecutor_Type = {
412409 .tp_as_sequence = & uop_as_sequence ,
413410 .tp_methods = executor_methods ,
414411 .tp_traverse = executor_traverse ,
415- .tp_clear = executor_clear ,
412+ .tp_clear = ( inquiry ) executor_clear ,
416413 .tp_is_gc = executor_is_gc ,
417414};
418415
@@ -1190,6 +1187,7 @@ init_cold_exit_executor(_PyExecutorObject *executor, int oparg)
11901187 inst -> opcode = _COLD_EXIT ;
11911188 inst -> oparg = oparg ;
11921189 executor -> vm_data .valid = true;
1190+ executor -> vm_data .linked = false;
11931191 for (int i = 0 ; i < BLOOM_FILTER_WORDS ; i ++ ) {
11941192 assert (executor -> vm_data .bloom .bits [i ] == 0 );
11951193 }
@@ -1328,7 +1326,7 @@ PyTypeObject _PyCounterExecutor_Type = {
13281326 .tp_dealloc = (destructor )counter_dealloc ,
13291327 .tp_methods = executor_methods ,
13301328 .tp_traverse = executor_traverse ,
1331- .tp_clear = executor_clear ,
1329+ .tp_clear = ( inquiry ) executor_clear ,
13321330};
13331331
13341332static int
@@ -1503,23 +1501,25 @@ link_executor(_PyExecutorObject *executor)
15031501 links -> next = NULL ;
15041502 }
15051503 else {
1506- _PyExecutorObject * next = head -> vm_data .links .next ;
1507- links -> previous = head ;
1508- links -> next = next ;
1509- if (next != NULL ) {
1510- next -> vm_data .links .previous = executor ;
1511- }
1512- head -> vm_data .links .next = executor ;
1504+ assert (head -> vm_data .links .previous == NULL );
1505+ links -> previous = NULL ;
1506+ links -> next = head ;
1507+ head -> vm_data .links .previous = executor ;
1508+ interp -> executor_list_head = executor ;
15131509 }
1514- executor -> vm_data .valid = true;
1510+ executor -> vm_data .linked = true;
15151511 /* executor_list_head must be first in list */
15161512 assert (interp -> executor_list_head -> vm_data .links .previous == NULL );
15171513}
15181514
15191515static void
15201516unlink_executor (_PyExecutorObject * executor )
15211517{
1518+ if (!executor -> vm_data .linked ) {
1519+ return ;
1520+ }
15221521 _PyExecutorLinkListNode * links = & executor -> vm_data .links ;
1522+ assert (executor -> vm_data .valid );
15231523 _PyExecutorObject * next = links -> next ;
15241524 _PyExecutorObject * prev = links -> previous ;
15251525 if (next != NULL ) {
@@ -1534,7 +1534,7 @@ unlink_executor(_PyExecutorObject *executor)
15341534 assert (interp -> executor_list_head == executor );
15351535 interp -> executor_list_head = next ;
15361536 }
1537- executor -> vm_data .valid = false;
1537+ executor -> vm_data .linked = false;
15381538}
15391539
15401540/* This must be called by optimizers before using the executor */
@@ -1548,31 +1548,52 @@ _Py_ExecutorInit(_PyExecutorObject *executor, const _PyBloomFilter *dependency_s
15481548 link_executor (executor );
15491549}
15501550
1551- /* This must be called by executors during dealloc */
1551+ /* Detaches the executor from the code object (if any) that
1552+ * holds a reference to it */
15521553void
1553- _Py_ExecutorClear (_PyExecutorObject * executor )
1554+ _Py_ExecutorDetach (_PyExecutorObject * executor )
15541555{
1555- if (!executor -> vm_data .valid ) {
1556- return ;
1557- }
1558- unlink_executor (executor );
15591556 PyCodeObject * code = executor -> vm_data .code ;
15601557 if (code == NULL ) {
15611558 return ;
15621559 }
1563- for (uint32_t i = 0 ; i < executor -> exit_count ; i ++ ) {
1564- Py_DECREF (executor -> exits [i ].executor );
1565- executor -> exits [i ].executor = & COLD_EXITS [i ];
1566- executor -> exits [i ].temperature = initial_unreachable_backoff_counter ();
1567- }
15681560 _Py_CODEUNIT * instruction = & _PyCode_CODE (code )[executor -> vm_data .index ];
15691561 assert (instruction -> op .code == ENTER_EXECUTOR );
15701562 int index = instruction -> op .arg ;
15711563 assert (code -> co_executors -> executors [index ] == executor );
15721564 instruction -> op .code = executor -> vm_data .opcode ;
15731565 instruction -> op .arg = executor -> vm_data .oparg ;
15741566 executor -> vm_data .code = NULL ;
1575- Py_CLEAR (code -> co_executors -> executors [index ]);
1567+ code -> co_executors -> executors [index ] = NULL ;
1568+ Py_DECREF (executor );
1569+ }
1570+
1571+ static int
1572+ executor_clear (_PyExecutorObject * executor )
1573+ {
1574+ if (!executor -> vm_data .valid ) {
1575+ return 0 ;
1576+ }
1577+ assert (executor -> vm_data .valid == 1 );
1578+ unlink_executor (executor );
1579+ executor -> vm_data .valid = 0 ;
1580+ /* It is possible for an executor to form a reference
1581+ * cycle with itself, so decref'ing a side exit could
1582+ * free the executor unless we hold a strong reference to it
1583+ */
1584+ Py_INCREF (executor );
1585+ for (uint32_t i = 0 ; i < executor -> exit_count ; i ++ ) {
1586+ const _PyExecutorObject * cold = & COLD_EXITS [i ];
1587+ const _PyExecutorObject * side = executor -> exits [i ].executor ;
1588+ executor -> exits [i ].temperature = initial_unreachable_backoff_counter ();
1589+ if (side != cold ) {
1590+ executor -> exits [i ].executor = cold ;
1591+ Py_DECREF (side );
1592+ }
1593+ }
1594+ _Py_ExecutorDetach (executor );
1595+ Py_DECREF (executor );
1596+ return 0 ;
15761597}
15771598
15781599void
@@ -1593,17 +1614,42 @@ _Py_Executors_InvalidateDependency(PyInterpreterState *interp, void *obj, int is
15931614 _Py_BloomFilter_Add (& obj_filter , obj );
15941615 /* Walk the list of executors */
15951616 /* TO DO -- Use a tree to avoid traversing as many objects */
1617+ bool no_memory = false;
1618+ PyObject * invalidate = PyList_New (0 );
1619+ if (invalidate == NULL ) {
1620+ PyErr_Clear ();
1621+ no_memory = true;
1622+ }
1623+ /* Clearing an executor can deallocate others, so we need to make a list of
1624+ * executors to invalidate first */
15961625 for (_PyExecutorObject * exec = interp -> executor_list_head ; exec != NULL ;) {
15971626 assert (exec -> vm_data .valid );
15981627 _PyExecutorObject * next = exec -> vm_data .links .next ;
15991628 if (bloom_filter_may_contain (& exec -> vm_data .bloom , & obj_filter )) {
1600- _Py_ExecutorClear (exec );
1629+ unlink_executor (exec );
1630+ if (no_memory ) {
1631+ exec -> vm_data .valid = 0 ;
1632+ } else {
1633+ if (PyList_Append (invalidate , (PyObject * )exec ) < 0 ) {
1634+ PyErr_Clear ();
1635+ no_memory = true;
1636+ exec -> vm_data .valid = 0 ;
1637+ }
1638+ }
16011639 if (is_invalidation ) {
16021640 OPT_STAT_INC (executors_invalidated );
16031641 }
16041642 }
16051643 exec = next ;
16061644 }
1645+ if (invalidate != NULL ) {
1646+ for (Py_ssize_t i = 0 ; i < PyList_GET_SIZE (invalidate ); i ++ ) {
1647+ _PyExecutorObject * exec = (_PyExecutorObject * )PyList_GET_ITEM (invalidate , i );
1648+ executor_clear (exec );
1649+ }
1650+ Py_DECREF (invalidate );
1651+ }
1652+ return ;
16071653}
16081654
16091655/* Invalidate all executors */
@@ -1612,12 +1658,13 @@ _Py_Executors_InvalidateAll(PyInterpreterState *interp, int is_invalidation)
16121658{
16131659 while (interp -> executor_list_head ) {
16141660 _PyExecutorObject * executor = interp -> executor_list_head ;
1661+ assert (executor -> vm_data .valid == 1 && executor -> vm_data .linked == 1 );
16151662 if (executor -> vm_data .code ) {
16161663 // Clear the entire code object so its co_executors array be freed:
16171664 _PyCode_Clear_Executors (executor -> vm_data .code );
16181665 }
16191666 else {
1620- _Py_ExecutorClear (executor );
1667+ executor_clear (executor );
16211668 }
16221669 if (is_invalidation ) {
16231670 OPT_STAT_INC (executors_invalidated );
0 commit comments