@@ -376,6 +376,74 @@ __type_propagate_TYPE_OVERWRITE(
376376 }
377377}
378378
379+ // src and dst are assumed to already be within the type context
380+ static void
381+ __type_propagate_TYPE_SWAP (
382+ _PyTier2TypeContext * type_context ,
383+ _Py_TYPENODE_t * src , _Py_TYPENODE_t * dst )
384+ {
385+ // Check if they are the same tree
386+ _Py_TYPENODE_t * srcrootref = src ;
387+ _Py_TYPENODE_t * dstrootref = dst ;
388+ uintptr_t dsttag = _Py_TYPENODE_GET_TAG (* dst );
389+ uintptr_t srctag = _Py_TYPENODE_GET_TAG (* src );
390+ switch (dsttag ) {
391+ case TYPE_REF : dstrootref = __typenode_get_rootptr (* dst );
392+ case TYPE_ROOT :
393+ switch (srctag ) {
394+ case TYPE_REF : srcrootref = __typenode_get_rootptr (* src );
395+ case TYPE_ROOT :
396+ if (srcrootref == dstrootref ) {
397+ // Same tree, no point swapping
398+ return ;
399+ }
400+ break ;
401+ default :
402+ Py_UNREACHABLE ();
403+ }
404+ break ;
405+ default :
406+ Py_UNREACHABLE ();
407+ }
408+
409+ // src and dst are different tree,
410+ // Make all children of src be children of dst and vice versa
411+
412+ _Py_TYPENODE_t src_child_test = _Py_TYPENODE_MAKE_REF (
413+ _Py_TYPENODE_CLEAR_TAG ((_Py_TYPENODE_t )src ));
414+ _Py_TYPENODE_t dst_child_test = _Py_TYPENODE_MAKE_REF (
415+ _Py_TYPENODE_CLEAR_TAG ((_Py_TYPENODE_t )dst ));
416+
417+ // Search locals for children
418+ int nlocals = type_context -> type_locals_len ;
419+ for (int i = 0 ; i < nlocals ; i ++ ) {
420+ _Py_TYPENODE_t * node_ptr = & (type_context -> type_locals [i ]);
421+ if (* node_ptr == src_child_test ) {
422+ * node_ptr = dst_child_test ;
423+ }
424+ else if (* node_ptr == dst_child_test ) {
425+ * node_ptr = src_child_test ;
426+ }
427+ }
428+
429+ // Search stack for children
430+ int nstack = type_context -> type_stack_len ;
431+ for (int i = 0 ; i < nstack ; i ++ ) {
432+ _Py_TYPENODE_t * node_ptr = & (type_context -> type_stack [i ]);
433+ if (* node_ptr == src_child_test ) {
434+ * node_ptr = dst_child_test ;
435+ }
436+ else if (* node_ptr == dst_child_test ) {
437+ * node_ptr = src_child_test ;
438+ }
439+ }
440+
441+ // Finally, actually swap the nodes
442+ * src ^= * dst ;
443+ * dst ^= * src ;
444+ * src ^= * dst ;
445+ }
446+
379447static void
380448__type_stack_shrink (_Py_TYPENODE_t * * type_stackptr , int idx )
381449{
@@ -489,6 +557,7 @@ type_propagate(
489557
490558#define TYPE_SET (src , dst , flag ) __type_propagate_TYPE_SET((src), (dst), (flag))
491559#define TYPE_OVERWRITE (src , dst , flag ) __type_propagate_TYPE_OVERWRITE(type_context, (src), (dst), (flag))
560+ #define TYPE_SWAP (src , dst ) __type_propagate_TYPE_SWAP(type_context, (src), (dst))
492561
493562#define STACK_GROW (idx ) *type_stackptr += (idx)
494563
@@ -504,8 +573,18 @@ type_propagate(
504573
505574 switch (opcode ) {
506575#include "tier2_typepropagator.c.h"
576+ TARGET (SWAP ) {
577+ _Py_TYPENODE_t * top = TYPESTACK_PEEK (1 );
578+ _Py_TYPENODE_t * bottom = TYPESTACK_PEEK (2 + (oparg - 2 ));
579+ TYPE_SWAP (top , bottom );
580+ break ;
581+ }
507582 default :
583+ #ifdef Py_DEBUG
584+ fprintf (stderr , "Unsupported opcode in type propagator: %s : %d\n" , _PyOpcode_OpName [opcode ], oparg );
585+ #else
508586 fprintf (stderr , "Unsupported opcode in type propagator: %d\n" , opcode );
587+ #endif
509588 Py_UNREACHABLE ();
510589 }
511590
0 commit comments