@@ -304,7 +304,7 @@ jl_datatype_t *jl_mk_builtin_func(jl_datatype_t *dt, const char *name, jl_fptr_a
304304    m -> isva  =  1 ;
305305    m -> nargs  =  2 ;
306306    jl_atomic_store_relaxed (& m -> primary_world , 1 );
307-     jl_atomic_store_relaxed (& m -> deleted_world , ~( size_t ) 0 );
307+     jl_atomic_store_relaxed (& m -> dispatch_status ,  METHOD_SIG_LATEST_ONLY  |  METHOD_SIG_LATEST_ONLY );
308308    m -> sig  =  (jl_value_t * )jl_anytuple_type ;
309309    m -> slot_syms  =  jl_an_empty_string ;
310310    m -> nospecialize  =  0 ;
@@ -315,7 +315,7 @@ jl_datatype_t *jl_mk_builtin_func(jl_datatype_t *dt, const char *name, jl_fptr_a
315315    JL_GC_PUSH2 (& m , & newentry );
316316
317317    newentry  =  jl_typemap_alloc (jl_anytuple_type , NULL , jl_emptysvec ,
318-             (jl_value_t * )m , jl_atomic_load_relaxed ( & m -> primary_world ),  jl_atomic_load_relaxed ( & m -> deleted_world ) );
318+             (jl_value_t * )m , 1 , ~( size_t ) 0 );
319319    jl_typemap_insert (& mt -> defs , (jl_value_t * )mt , newentry , jl_cachearg_offset (mt ));
320320
321321    jl_method_instance_t  * mi  =  jl_get_specialized (m , (jl_value_t * )jl_anytuple_type , jl_emptysvec );
@@ -1917,7 +1917,7 @@ static int is_replacing(char ambig, jl_value_t *type, jl_method_t *m, jl_method_
19171917        // since m2 was also a previous match over isect, 
19181918        // see if m was previously dominant over all m2 
19191919        // or if this was already ambiguous before 
1920-         if  (ambig  ! =morespec_is  &&  !jl_type_morespecific (m -> sig , m2 -> sig )) {
1920+         if  (ambig  = =morespec_is  &&  !jl_type_morespecific (m -> sig , m2 -> sig )) {
19211921            // m and m2 were previously ambiguous over the full intersection of mi with type, and will still be ambiguous with addition of type 
19221922            return  0 ;
19231923        }
@@ -2251,17 +2251,22 @@ JL_DLLEXPORT void jl_method_table_disable(jl_methtable_t *mt, jl_method_t *metho
22512251    JL_LOCK (& world_counter_lock );
22522252    if  (!jl_atomic_load_relaxed (& allow_new_worlds ))
22532253        jl_error ("Method changes have been disabled via a call to disable_new_worlds." );
2254-     JL_LOCK (& mt -> writelock );
2255-     // Narrow the world age on the method to make it uncallable 
2256-     size_t  world  =  jl_atomic_load_relaxed (& jl_world_counter );
2257-     assert (method  ==  methodentry -> func .method );
2258-     assert (jl_atomic_load_relaxed (& method -> deleted_world ) ==  ~(size_t )0 );
2259-     jl_atomic_store_relaxed (& method -> deleted_world , world );
2260-     jl_atomic_store_relaxed (& methodentry -> max_world , world );
2261-     jl_method_table_invalidate (mt , method , world );
2262-     jl_atomic_store_release (& jl_world_counter , world  +  1 );
2263-     JL_UNLOCK (& mt -> writelock );
2254+     int  enabled  =  jl_atomic_load_relaxed (& methodentry -> max_world ) ==  ~(size_t )0 ;
2255+     if  (enabled ) {
2256+         JL_LOCK (& mt -> writelock );
2257+         // Narrow the world age on the method to make it uncallable 
2258+         size_t  world  =  jl_atomic_load_relaxed (& jl_world_counter );
2259+         assert (method  ==  methodentry -> func .method );
2260+         jl_atomic_store_relaxed (& method -> dispatch_status , 0 );
2261+         assert (jl_atomic_load_relaxed (& methodentry -> max_world ) ==  ~(size_t )0 );
2262+         jl_atomic_store_relaxed (& methodentry -> max_world , world );
2263+         jl_method_table_invalidate (mt , method , world );
2264+         jl_atomic_store_release (& jl_world_counter , world  +  1 );
2265+         JL_UNLOCK (& mt -> writelock );
2266+     }
22642267    JL_UNLOCK (& world_counter_lock );
2268+     if  (!enabled )
2269+         jl_errorf ("Method of %s already disabled" , jl_symbol_name (method -> name ));
22652270}
22662271
22672272static  int  jl_type_intersection2 (jl_value_t  * t1 , jl_value_t  * t2 , jl_value_t  * * isect  JL_REQUIRE_ROOTED_SLOT , jl_value_t  * * isect2  JL_REQUIRE_ROOTED_SLOT )
@@ -2301,9 +2306,9 @@ jl_typemap_entry_t *jl_method_table_add(jl_methtable_t *mt, jl_method_t *method,
23012306    JL_LOCK (& mt -> writelock );
23022307    // add our new entry 
23032308    assert (jl_atomic_load_relaxed (& method -> primary_world ) ==  ~(size_t )0 ); // min-world 
2304-     assert (jl_atomic_load_relaxed (& method -> deleted_world )  ==  1 );  // max-world 
2305-     newentry   =   jl_typemap_alloc (( jl_tupletype_t * ) method -> sig ,  simpletype ,  jl_emptysvec , ( jl_value_t * ) method , 
2306-              jl_atomic_load_relaxed ( & method -> primary_world ),  jl_atomic_load_relaxed ( & method -> deleted_world ) );
2309+     assert (( jl_atomic_load_relaxed (& method -> dispatch_status )  &   METHOD_SIG_LATEST_WHICH )  ==  0 ); 
2310+     assert (( jl_atomic_load_relaxed ( & method -> dispatch_status )  &   METHOD_SIG_LATEST_ONLY )  ==   0 ); 
2311+     newentry   =   jl_typemap_alloc (( jl_tupletype_t * ) method -> sig ,  simpletype ,  jl_emptysvec , ( jl_value_t * ) method , ~( size_t ) 0 ,  1 );
23072312    jl_typemap_insert (& mt -> defs , (jl_value_t * )mt , newentry , jl_cachearg_offset (mt ));
23082313    update_max_args (mt , method -> sig );
23092314    JL_UNLOCK (& mt -> writelock );
@@ -2324,7 +2329,8 @@ void jl_method_table_activate(jl_methtable_t *mt, jl_typemap_entry_t *newentry)
23242329    JL_LOCK (& mt -> writelock );
23252330    size_t  world  =  jl_atomic_load_relaxed (& method -> primary_world );
23262331    assert (world  ==  jl_atomic_load_relaxed (& jl_world_counter ) +  1 ); // min-world 
2327-     assert (jl_atomic_load_relaxed (& method -> deleted_world ) ==  ~(size_t )0 ); // max-world 
2332+     assert ((jl_atomic_load_relaxed (& method -> dispatch_status ) &  METHOD_SIG_LATEST_WHICH ) ==  0 );
2333+     assert ((jl_atomic_load_relaxed (& method -> dispatch_status ) &  METHOD_SIG_LATEST_ONLY ) ==  0 );
23282334    assert (jl_atomic_load_relaxed (& newentry -> min_world ) ==  ~(size_t )0 );
23292335    assert (jl_atomic_load_relaxed (& newentry -> max_world ) ==  1 );
23302336    jl_atomic_store_relaxed (& newentry -> min_world , world );
@@ -2339,12 +2345,17 @@ void jl_method_table_activate(jl_methtable_t *mt, jl_typemap_entry_t *newentry)
23392345    // then check what entries we replaced 
23402346    oldvalue  =  get_intersect_matches (jl_atomic_load_relaxed (& mt -> defs ), newentry , & replaced , jl_cachearg_offset (mt ), max_world );
23412347    int  invalidated  =  0 ;
2348+     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` 
23422349    if  (replaced ) {
23432350        oldvalue  =  (jl_value_t * )replaced ;
2351+         jl_method_t  * m  =  replaced -> func .method ;
23442352        invalidated  =  1 ;
2345-         method_overwrite (newentry , replaced -> func . method );
2353+         method_overwrite (newentry , m );
23462354        // this is an optimized version of below, given we know the type-intersection is exact 
2347-         jl_method_table_invalidate (mt , replaced -> func .method , max_world );
2355+         jl_method_table_invalidate (mt , m , max_world );
2356+         int  m_dispatch  =  jl_atomic_load_relaxed (& m -> dispatch_status );
2357+         jl_atomic_store_relaxed (& m -> dispatch_status , 0 );
2358+         only  =  m_dispatch  &  METHOD_SIG_LATEST_ONLY ;
23482359    }
23492360    else  {
23502361        jl_method_t  * const  * d ;
@@ -2416,8 +2427,10 @@ void jl_method_table_activate(jl_methtable_t *mt, jl_typemap_entry_t *newentry)
24162427            memset (morespec , morespec_unknown , n );
24172428            for  (j  =  0 ; j  <  n ; j ++ ) {
24182429                jl_method_t  * m  =  d [j ];
2419-                 if  (morespec [j ] ==  (char )morespec_is )
2430+                 if  (morespec [j ] ==  (char )morespec_is ) {
2431+                     only  =  0 ;
24202432                    continue ;
2433+                 }
24212434                loctag  =  jl_atomic_load_relaxed (& m -> specializations ); // use loctag for a gcroot 
24222435                _Atomic(jl_method_instance_t * ) * data ;
24232436                size_t  l ;
@@ -2447,7 +2460,7 @@ void jl_method_table_activate(jl_methtable_t *mt, jl_typemap_entry_t *newentry)
24472460                            // not actually shadowing--the existing method is still better 
24482461                            break ;
24492462                        if  (ambig  ==  morespec_unknown )
2450-                             ambig  =  jl_type_morespecific (type , m -> sig ) ? morespec_is  : morespec_isnot ;
2463+                             ambig  =  jl_type_morespecific (type , m -> sig ) ? morespec_isnot  : morespec_is ;
24512464                        // replacing a method--see if this really was the selected method previously 
24522465                        // over the intersection (not ambiguous) and the new method will be selected now (morespec_is) 
24532466                        int  replaced_dispatch  =  is_replacing (ambig , type , m , d , n , isect , isect2 , morespec );
@@ -2464,6 +2477,20 @@ void jl_method_table_activate(jl_methtable_t *mt, jl_typemap_entry_t *newentry)
24642477                        invalidated  |= invalidatedmi ;
24652478                    }
24662479                }
2480+                 // now compute and store updates to METHOD_SIG_LATEST_ONLY 
2481+                 int  m_dispatch  =  jl_atomic_load_relaxed (& m -> dispatch_status );
2482+                 if  (m_dispatch  &  METHOD_SIG_LATEST_ONLY ) {
2483+                     if  (morespec [j ] ==  (char )morespec_unknown )
2484+                         morespec [j ] =  (char )(jl_type_morespecific (m -> sig , type ) ? morespec_is  : morespec_isnot );
2485+                     if  (morespec [j ] ==  (char )morespec_isnot )
2486+                         jl_atomic_store_relaxed (& m -> dispatch_status , ~METHOD_SIG_LATEST_ONLY  &  m_dispatch );
2487+                 }
2488+                 if  (only ) {
2489+                     if  (morespec [j ] ==  (char )morespec_is  ||  ambig  ==  morespec_is  || 
2490+                         (ambig  ==  morespec_unknown  &&  !jl_type_morespecific (type , m -> sig ))) {
2491+                         only  =  0 ;
2492+                     }
2493+                 }
24672494            }
24682495            if  (jl_array_nrows (oldmi )) {
24692496                // search mt->cache and leafcache and drop anything that might overlap with the new method 
@@ -2494,7 +2521,8 @@ void jl_method_table_activate(jl_methtable_t *mt, jl_typemap_entry_t *newentry)
24942521        loctag  =  jl_cstr_to_string ("jl_method_table_insert" );
24952522        jl_array_ptr_1d_push (_jl_debug_method_invalidation , loctag );
24962523    }
2497-     jl_atomic_store_relaxed (& newentry -> max_world , jl_atomic_load_relaxed (& method -> deleted_world ));
2524+     jl_atomic_store_relaxed (& newentry -> max_world , ~(size_t )0 );
2525+     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 
24982526    JL_UNLOCK (& mt -> writelock );
24992527    JL_GC_POP ();
25002528}
@@ -2508,7 +2536,6 @@ JL_DLLEXPORT void jl_method_table_insert(jl_methtable_t *mt, jl_method_t *method
25082536        jl_error ("Method changes have been disabled via a call to disable_new_worlds." );
25092537    size_t  world  =  jl_atomic_load_relaxed (& jl_world_counter ) +  1 ;
25102538    jl_atomic_store_relaxed (& method -> primary_world , world );
2511-     jl_atomic_store_relaxed (& method -> deleted_world , ~(size_t )0 );
25122539    jl_method_table_activate (mt , newentry );
25132540    jl_atomic_store_release (& jl_world_counter , world );
25142541    JL_UNLOCK (& world_counter_lock );
@@ -3906,6 +3933,8 @@ static int ml_matches_visitor(jl_typemap_entry_t *ml, struct typemap_intersectio
39063933            closure -> match .min_valid  =  max_world  +  1 ;
39073934        return  1 ;
39083935    }
3936+     if  (closure -> match .max_valid  >  max_world )
3937+         closure -> match .max_valid  =  max_world ;
39093938    jl_method_t  * meth  =  ml -> func .method ;
39103939    if  (closure -> lim  >= 0  &&  jl_is_dispatch_tupletype (meth -> sig )) {
39113940        int  replaced  =  0 ;
@@ -4578,12 +4607,9 @@ static jl_value_t *ml_matches(jl_methtable_t *mt,
45784607        jl_method_t  * m  =  matc -> method ;
45794608        // method applicability is the same as typemapentry applicability 
45804609        size_t  min_world  =  jl_atomic_load_relaxed (& m -> primary_world );
4581-         size_t  max_world  =  jl_atomic_load_relaxed (& m -> deleted_world );
45824610        // intersect the env valid range with method lookup's inclusive valid range 
45834611        if  (env .match .min_valid  <  min_world )
45844612            env .match .min_valid  =  min_world ;
4585-         if  (env .match .max_valid  >  max_world )
4586-             env .match .max_valid  =  max_world ;
45874613    }
45884614    if  (mt  &&  cache_result  &&  ((jl_datatype_t * )unw )-> isdispatchtuple ) { // cache_result parameter keeps this from being recursive 
45894615        if  (len  ==  1  &&  !has_ambiguity ) {
0 commit comments