@@ -2140,12 +2140,6 @@ static int jl_type_intersection2(jl_value_t *t1, jl_value_t *t2, jl_value_t **is
21402140}
21412141
21422142
2143- enum  morespec_options  {
2144-     morespec_unknown ,
2145-     morespec_isnot ,
2146-     morespec_is 
2147- };
2148- 
21492143// check if `type` is replacing `m` with an ambiguity here, given other methods in `d` that already match it 
21502144static  int  is_replacing (char  ambig , jl_value_t  * type , jl_method_t  * m , jl_method_t  * const  * d , size_t  n , jl_value_t  * isect , jl_value_t  * isect2 , char  * morespec )
21512145{
@@ -2155,17 +2149,15 @@ static int is_replacing(char ambig, jl_value_t *type, jl_method_t *m, jl_method_
21552149        // see if m2 also fully covered this intersection 
21562150        if  (m  ==  m2  ||  !(jl_subtype (isect , m2 -> sig ) ||  (isect2  &&  jl_subtype (isect2 , m2 -> sig ))))
21572151            continue ;
2158-         if  (morespec [k ] ==  (char )morespec_unknown )
2159-             morespec [k ] =  (char )(jl_type_morespecific (m2 -> sig , type ) ? morespec_is  : morespec_isnot );
2160-         if  (morespec [k ] ==  (char )morespec_is )
2152+         if  (morespec [k ])
21612153            // not actually shadowing this--m2 will still be better 
21622154            return  0 ;
21632155        // if type is not more specific than m (thus now dominating it) 
21642156        // then there is a new ambiguity here, 
21652157        // since m2 was also a previous match over isect, 
21662158        // see if m was previously dominant over all m2 
21672159        // or if this was already ambiguous before 
2168-         if  (ambig  ==   morespec_is   &&  !jl_type_morespecific (m -> sig , m2 -> sig )) {
2160+         if  (ambig  &&  !jl_type_morespecific (m -> sig , m2 -> sig )) {
21692161            // m and m2 were previously ambiguous over the full intersection of mi with type, and will still be ambiguous with addition of type 
21702162            return  0 ;
21712163        }
@@ -2659,17 +2651,27 @@ void jl_method_table_activate(jl_typemap_entry_t *newentry)
26592651    oldvalue  =  get_intersect_matches (jl_atomic_load_relaxed (& mt -> defs ), newentry , & replaced , max_world );
26602652
26612653    int  invalidated  =  0 ;
2662-     int  only  =  !(jl_atomic_load_relaxed (& method -> dispatch_status ) &  METHOD_SIG_PRECOMPILE_MANY ); // will compute if this will be currently the only result that would returned from `ml_matches` given `sig` 
2654+     int  dispatch_bits  =  METHOD_SIG_LATEST_WHICH ; // Always set LATEST_WHICH 
2655+     // Check precompiled dispatch status bits 
2656+     int  precompiled_status  =  jl_atomic_load_relaxed (& method -> dispatch_status );
2657+     if  (!(precompiled_status  &  METHOD_SIG_PRECOMPILE_MANY ))
2658+         dispatch_bits  |= METHOD_SIG_LATEST_ONLY ; // Tentatively set, will be cleared if not applicable 
2659+     if  (precompiled_status  &  METHOD_SIG_PRECOMPILE_HAS_NOTMORESPECIFIC )
2660+         dispatch_bits  |= METHOD_SIG_LATEST_HAS_NOTMORESPECIFIC ;
26632661    if  (replaced ) {
26642662        oldvalue  =  (jl_value_t * )replaced ;
26652663        jl_method_t  * m  =  replaced -> func .method ;
26662664        invalidated  =  1 ;
26672665        method_overwrite (newentry , m );
2668-         // this  is an optimized version of below, given we know the type-intersection is exact 
2666+         // This  is an optimized version of below, given we know the type-intersection is exact 
26692667        jl_method_table_invalidate (m , max_world );
26702668        int  m_dispatch  =  jl_atomic_load_relaxed (& m -> dispatch_status );
2671-         jl_atomic_store_relaxed (& m -> dispatch_status , 0 );
2672-         only  =  m_dispatch  &  METHOD_SIG_LATEST_ONLY ;
2669+         // Clear METHOD_SIG_LATEST_ONLY and METHOD_SIG_LATEST_WHICH bits, only keeping NOTMORESPECIFIC 
2670+         jl_atomic_store_relaxed (& m -> dispatch_status , m_dispatch  &  METHOD_SIG_LATEST_HAS_NOTMORESPECIFIC );
2671+         // Edge case: don't set dispatch_bits |= METHOD_SIG_LATEST_HAS_NOTMORESPECIFIC unconditionally since `m` is not an visible method for invalidations 
2672+         dispatch_bits  |= (m_dispatch  &  METHOD_SIG_LATEST_HAS_NOTMORESPECIFIC );
2673+         if  (!(m_dispatch  &  METHOD_SIG_LATEST_ONLY ))
2674+             dispatch_bits  &= ~METHOD_SIG_LATEST_ONLY ;
26732675    }
26742676    else  {
26752677        jl_method_t  * const  * d ;
@@ -2685,13 +2687,28 @@ void jl_method_table_activate(jl_typemap_entry_t *newentry)
26852687
26862688            oldmi  =  jl_alloc_vec_any (0 );
26872689            char  * morespec  =  (char * )alloca (n );
2688-             memset (morespec , morespec_unknown , n );
2690+             // Compute all morespec values upfront 
2691+             for  (j  =  0 ; j  <  n ; j ++ )
2692+                 morespec [j ] =  (char )jl_type_morespecific (d [j ]-> sig , type );
26892693            for  (j  =  0 ; j  <  n ; j ++ ) {
26902694                jl_method_t  * m  =  d [j ];
2691-                 if  (morespec [j ] ==  (char )morespec_is ) {
2692-                     only  =  0 ;
2693-                     continue ;
2695+                 // Compute ambig state: is there an ambiguity between new method and old m? 
2696+                 char  ambig  =  !morespec [j ] &&  !jl_type_morespecific (type , m -> sig );
2697+                 // Compute updates to the dispatch state bits 
2698+                 int  m_dispatch  =  jl_atomic_load_relaxed (& m -> dispatch_status );
2699+                 if  (morespec [j ] ||  ambig ) {
2700+                     // !morespecific(new, old) 
2701+                     dispatch_bits  &= ~METHOD_SIG_LATEST_ONLY ;
2702+                     m_dispatch  |= METHOD_SIG_LATEST_HAS_NOTMORESPECIFIC ;
2703+                 }
2704+                 if  (!morespec [j ]) {
2705+                     // !morespecific(old, new) 
2706+                     dispatch_bits  |= METHOD_SIG_LATEST_HAS_NOTMORESPECIFIC ;
2707+                     m_dispatch  &= ~METHOD_SIG_LATEST_ONLY ;
26942708                }
2709+                 jl_atomic_store_relaxed (& m -> dispatch_status , m_dispatch );
2710+                 if  (morespec [j ])
2711+                     continue ;
26952712                loctag  =  jl_atomic_load_relaxed (& m -> specializations ); // use loctag for a gcroot 
26962713                _Atomic(jl_method_instance_t * ) * data ;
26972714                size_t  l ;
@@ -2703,27 +2720,19 @@ void jl_method_table_activate(jl_typemap_entry_t *newentry)
27032720                    data  =  (_Atomicjl_method_instance_t * )* ) & loctag ;
27042721                    l  =  1 ;
27052722                }
2706-                 enum  morespec_options  ambig  =  morespec_unknown ;
27072723                for  (size_t  i  =  0 ; i  <  l ; i ++ ) {
27082724                    jl_method_instance_t  * mi  =  jl_atomic_load_relaxed (& data [i ]);
27092725                    if  ((jl_value_t * )mi  ==  jl_nothing )
27102726                        continue ;
27112727                    isect3  =  jl_type_intersection (m -> sig , (jl_value_t * )mi -> specTypes );
27122728                    if  (jl_type_intersection2 (type , isect3 , & isect , & isect2 )) {
2729+                         // Replacing a method--see if this really was the selected method previously 
2730+                         // over the intersection (not ambiguous) and the new method will be selected now (morespec_is). 
27132731                        // TODO: this only checks pair-wise for ambiguities, but the ambiguities could arise from the interaction of multiple methods 
27142732                        // and thus might miss a case where we introduce an ambiguity between two existing methods 
27152733                        // We could instead work to sort this into 3 groups `morespecific .. ambiguous .. lesspecific`, with `type` in ambiguous, 
27162734                        // such that everything in `morespecific` dominates everything in `ambiguous`, and everything in `ambiguous` dominates everything in `lessspecific` 
27172735                        // And then compute where each isect falls, and whether it changed group--necessitating invalidation--or not. 
2718-                         if  (morespec [j ] ==  (char )morespec_unknown )
2719-                             morespec [j ] =  (char )(jl_type_morespecific (m -> sig , type ) ? morespec_is  : morespec_isnot );
2720-                         if  (morespec [j ] ==  (char )morespec_is )
2721-                             // not actually shadowing--the existing method is still better 
2722-                             break ;
2723-                         if  (ambig  ==  morespec_unknown )
2724-                             ambig  =  jl_type_morespecific (type , m -> sig ) ? morespec_isnot  : morespec_is ;
2725-                         // replacing a method--see if this really was the selected method previously 
2726-                         // over the intersection (not ambiguous) and the new method will be selected now (morespec_is) 
27272736                        int  replaced_dispatch  =  is_replacing (ambig , type , m , d , n , isect , isect2 , morespec );
27282737                        // found that this specialization dispatch got replaced by m 
27292738                        // call invalidate_backedges(mi, max_world, "jl_method_table_insert"); 
@@ -2740,20 +2749,6 @@ void jl_method_table_activate(jl_typemap_entry_t *newentry)
27402749                        invalidated  |= invalidatedmi ;
27412750                    }
27422751                }
2743-                 // now compute and store updates to METHOD_SIG_LATEST_ONLY 
2744-                 int  m_dispatch  =  jl_atomic_load_relaxed (& m -> dispatch_status );
2745-                 if  (m_dispatch  &  METHOD_SIG_LATEST_ONLY ) {
2746-                     if  (morespec [j ] ==  (char )morespec_unknown )
2747-                         morespec [j ] =  (char )(jl_type_morespecific (m -> sig , type ) ? morespec_is  : morespec_isnot );
2748-                     if  (morespec [j ] ==  (char )morespec_isnot )
2749-                         jl_atomic_store_relaxed (& m -> dispatch_status , ~METHOD_SIG_LATEST_ONLY  &  m_dispatch );
2750-                 }
2751-                 if  (only ) {
2752-                     if  (morespec [j ] ==  (char )morespec_is  ||  ambig  ==  morespec_is  || 
2753-                         (ambig  ==  morespec_unknown  &&  !jl_type_morespecific (type , m -> sig ))) {
2754-                         only  =  0 ;
2755-                     }
2756-                 }
27572752            }
27582753        }
27592754
@@ -2802,7 +2797,7 @@ void jl_method_table_activate(jl_typemap_entry_t *newentry)
28022797        jl_array_ptr_1d_push (_jl_debug_method_invalidation , loctag );
28032798    }
28042799    jl_atomic_store_relaxed (& newentry -> max_world , ~(size_t )0 );
2805-     jl_atomic_store_relaxed (& method -> dispatch_status , METHOD_SIG_LATEST_WHICH  | ( only  ?  METHOD_SIG_LATEST_ONLY  :  0 ) ); // TODO: this should be sequenced fully after the world counter store 
2800+     jl_atomic_store_relaxed (& method -> dispatch_status , dispatch_bits ); // TODO: this should be sequenced fully after the world counter store 
28062801    JL_GC_POP ();
28072802}
28082803
0 commit comments