@@ -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 = (_Atomic (jl_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