@@ -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