@@ -2140,12 +2140,6 @@ static int jl_type_intersection2(jl_value_t *t1, jl_value_t *t2, jl_value_t **is
2140
2140
}
2141
2141
2142
2142
2143
- enum morespec_options {
2144
- morespec_unknown ,
2145
- morespec_isnot ,
2146
- morespec_is
2147
- };
2148
-
2149
2143
// check if `type` is replacing `m` with an ambiguity here, given other methods in `d` that already match it
2150
2144
static 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 )
2151
2145
{
@@ -2155,17 +2149,15 @@ static int is_replacing(char ambig, jl_value_t *type, jl_method_t *m, jl_method_
2155
2149
// see if m2 also fully covered this intersection
2156
2150
if (m == m2 || !(jl_subtype (isect , m2 -> sig ) || (isect2 && jl_subtype (isect2 , m2 -> sig ))))
2157
2151
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 ])
2161
2153
// not actually shadowing this--m2 will still be better
2162
2154
return 0 ;
2163
2155
// if type is not more specific than m (thus now dominating it)
2164
2156
// then there is a new ambiguity here,
2165
2157
// since m2 was also a previous match over isect,
2166
2158
// see if m was previously dominant over all m2
2167
2159
// 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 )) {
2169
2161
// m and m2 were previously ambiguous over the full intersection of mi with type, and will still be ambiguous with addition of type
2170
2162
return 0 ;
2171
2163
}
@@ -2659,17 +2651,27 @@ void jl_method_table_activate(jl_typemap_entry_t *newentry)
2659
2651
oldvalue = get_intersect_matches (jl_atomic_load_relaxed (& mt -> defs ), newentry , & replaced , max_world );
2660
2652
2661
2653
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 ;
2663
2661
if (replaced ) {
2664
2662
oldvalue = (jl_value_t * )replaced ;
2665
2663
jl_method_t * m = replaced -> func .method ;
2666
2664
invalidated = 1 ;
2667
2665
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
2669
2667
jl_method_table_invalidate (m , max_world );
2670
2668
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 ;
2673
2675
}
2674
2676
else {
2675
2677
jl_method_t * const * d ;
@@ -2685,13 +2687,28 @@ void jl_method_table_activate(jl_typemap_entry_t *newentry)
2685
2687
2686
2688
oldmi = jl_alloc_vec_any (0 );
2687
2689
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 );
2689
2693
for (j = 0 ; j < n ; j ++ ) {
2690
2694
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 ;
2694
2708
}
2709
+ jl_atomic_store_relaxed (& m -> dispatch_status , m_dispatch );
2710
+ if (morespec [j ])
2711
+ continue ;
2695
2712
loctag = jl_atomic_load_relaxed (& m -> specializations ); // use loctag for a gcroot
2696
2713
_Atomic(jl_method_instance_t * ) * data ;
2697
2714
size_t l ;
@@ -2703,27 +2720,19 @@ void jl_method_table_activate(jl_typemap_entry_t *newentry)
2703
2720
data = (_Atomic (jl_method_instance_t * )* ) & loctag ;
2704
2721
l = 1 ;
2705
2722
}
2706
- enum morespec_options ambig = morespec_unknown ;
2707
2723
for (size_t i = 0 ; i < l ; i ++ ) {
2708
2724
jl_method_instance_t * mi = jl_atomic_load_relaxed (& data [i ]);
2709
2725
if ((jl_value_t * )mi == jl_nothing )
2710
2726
continue ;
2711
2727
isect3 = jl_type_intersection (m -> sig , (jl_value_t * )mi -> specTypes );
2712
2728
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).
2713
2731
// TODO: this only checks pair-wise for ambiguities, but the ambiguities could arise from the interaction of multiple methods
2714
2732
// and thus might miss a case where we introduce an ambiguity between two existing methods
2715
2733
// We could instead work to sort this into 3 groups `morespecific .. ambiguous .. lesspecific`, with `type` in ambiguous,
2716
2734
// such that everything in `morespecific` dominates everything in `ambiguous`, and everything in `ambiguous` dominates everything in `lessspecific`
2717
2735
// 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)
2727
2736
int replaced_dispatch = is_replacing (ambig , type , m , d , n , isect , isect2 , morespec );
2728
2737
// found that this specialization dispatch got replaced by m
2729
2738
// call invalidate_backedges(mi, max_world, "jl_method_table_insert");
@@ -2740,20 +2749,6 @@ void jl_method_table_activate(jl_typemap_entry_t *newentry)
2740
2749
invalidated |= invalidatedmi ;
2741
2750
}
2742
2751
}
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
- }
2757
2752
}
2758
2753
}
2759
2754
@@ -2802,7 +2797,7 @@ void jl_method_table_activate(jl_typemap_entry_t *newentry)
2802
2797
jl_array_ptr_1d_push (_jl_debug_method_invalidation , loctag );
2803
2798
}
2804
2799
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
2806
2801
JL_GC_POP ();
2807
2802
}
2808
2803
0 commit comments