@@ -296,7 +296,7 @@ void jl_mk_builtin_func(jl_datatype_t *dt, jl_sym_t *sname, jl_fptr_args_t fptr)
296296 m -> isva = 1 ;
297297 m -> nargs = 2 ;
298298 jl_atomic_store_relaxed (& m -> primary_world , 1 );
299- jl_atomic_store_relaxed (& m -> deleted_world , ~( size_t ) 0 );
299+ jl_atomic_store_relaxed (& m -> dispatch_status , METHOD_SIG_LATEST_ONLY | METHOD_SIG_LATEST_ONLY );
300300 m -> sig = (jl_value_t * )jl_anytuple_type ;
301301 m -> slot_syms = jl_an_empty_string ;
302302 m -> nospecialize = 0 ;
@@ -307,7 +307,7 @@ void jl_mk_builtin_func(jl_datatype_t *dt, jl_sym_t *sname, jl_fptr_args_t fptr)
307307 JL_GC_PUSH2 (& m , & newentry );
308308
309309 newentry = jl_typemap_alloc (jl_anytuple_type , NULL , jl_emptysvec ,
310- (jl_value_t * )m , jl_atomic_load_relaxed ( & m -> primary_world ), jl_atomic_load_relaxed ( & m -> deleted_world ) );
310+ (jl_value_t * )m , 1 , ~( size_t ) 0 );
311311 jl_typemap_insert (& mt -> defs , (jl_value_t * )mt , newentry , jl_cachearg_offset (mt ));
312312
313313 jl_method_instance_t * mi = jl_get_specialized (m , (jl_value_t * )jl_anytuple_type , jl_emptysvec );
@@ -1908,7 +1908,7 @@ static int is_replacing(char ambig, jl_value_t *type, jl_method_t *m, jl_method_
19081908 // since m2 was also a previous match over isect,
19091909 // see if m was previously dominant over all m2
19101910 // or if this was already ambiguous before
1911- if (ambig ! = morespec_is && !jl_type_morespecific (m -> sig , m2 -> sig )) {
1911+ if (ambig = = morespec_is && !jl_type_morespecific (m -> sig , m2 -> sig )) {
19121912 // m and m2 were previously ambiguous over the full intersection of mi with type, and will still be ambiguous with addition of type
19131913 return 0 ;
19141914 }
@@ -2242,17 +2242,22 @@ JL_DLLEXPORT void jl_method_table_disable(jl_methtable_t *mt, jl_method_t *metho
22422242 JL_LOCK (& world_counter_lock );
22432243 if (!jl_atomic_load_relaxed (& allow_new_worlds ))
22442244 jl_error ("Method changes have been disabled via a call to disable_new_worlds." );
2245- JL_LOCK (& mt -> writelock );
2246- // Narrow the world age on the method to make it uncallable
2247- size_t world = jl_atomic_load_relaxed (& jl_world_counter );
2248- assert (method == methodentry -> func .method );
2249- assert (jl_atomic_load_relaxed (& method -> deleted_world ) == ~(size_t )0 );
2250- jl_atomic_store_relaxed (& method -> deleted_world , world );
2251- jl_atomic_store_relaxed (& methodentry -> max_world , world );
2252- jl_method_table_invalidate (mt , method , world );
2253- jl_atomic_store_release (& jl_world_counter , world + 1 );
2254- JL_UNLOCK (& mt -> writelock );
2245+ int enabled = jl_atomic_load_relaxed (& methodentry -> max_world ) == ~(size_t )0 ;
2246+ if (enabled ) {
2247+ JL_LOCK (& mt -> writelock );
2248+ // Narrow the world age on the method to make it uncallable
2249+ size_t world = jl_atomic_load_relaxed (& jl_world_counter );
2250+ assert (method == methodentry -> func .method );
2251+ jl_atomic_store_relaxed (& method -> dispatch_status , 0 );
2252+ assert (jl_atomic_load_relaxed (& methodentry -> max_world ) == ~(size_t )0 );
2253+ jl_atomic_store_relaxed (& methodentry -> max_world , world );
2254+ jl_method_table_invalidate (mt , method , world );
2255+ jl_atomic_store_release (& jl_world_counter , world + 1 );
2256+ JL_UNLOCK (& mt -> writelock );
2257+ }
22552258 JL_UNLOCK (& world_counter_lock );
2259+ if (!enabled )
2260+ jl_errorf ("Method of %s already disabled" , jl_symbol_name (method -> name ));
22562261}
22572262
22582263static 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 )
@@ -2292,9 +2297,9 @@ jl_typemap_entry_t *jl_method_table_add(jl_methtable_t *mt, jl_method_t *method,
22922297 JL_LOCK (& mt -> writelock );
22932298 // add our new entry
22942299 assert (jl_atomic_load_relaxed (& method -> primary_world ) == ~(size_t )0 ); // min-world
2295- assert (jl_atomic_load_relaxed (& method -> deleted_world ) == 1 ); // max-world
2296- newentry = jl_typemap_alloc (( jl_tupletype_t * ) method -> sig , simpletype , jl_emptysvec , ( jl_value_t * ) method ,
2297- jl_atomic_load_relaxed ( & method -> primary_world ), jl_atomic_load_relaxed ( & method -> deleted_world ) );
2300+ assert (( jl_atomic_load_relaxed (& method -> dispatch_status ) & METHOD_SIG_LATEST_WHICH ) == 0 );
2301+ assert (( jl_atomic_load_relaxed ( & method -> dispatch_status ) & METHOD_SIG_LATEST_ONLY ) == 0 );
2302+ newentry = jl_typemap_alloc (( jl_tupletype_t * ) method -> sig , simpletype , jl_emptysvec , ( jl_value_t * ) method , ~( size_t ) 0 , 1 );
22982303 jl_typemap_insert (& mt -> defs , (jl_value_t * )mt , newentry , jl_cachearg_offset (mt ));
22992304 update_max_args (mt , method -> sig );
23002305 JL_UNLOCK (& mt -> writelock );
@@ -2315,7 +2320,8 @@ void jl_method_table_activate(jl_methtable_t *mt, jl_typemap_entry_t *newentry)
23152320 JL_LOCK (& mt -> writelock );
23162321 size_t world = jl_atomic_load_relaxed (& method -> primary_world );
23172322 assert (world == jl_atomic_load_relaxed (& jl_world_counter ) + 1 ); // min-world
2318- assert (jl_atomic_load_relaxed (& method -> deleted_world ) == ~(size_t )0 ); // max-world
2323+ assert ((jl_atomic_load_relaxed (& method -> dispatch_status ) & METHOD_SIG_LATEST_WHICH ) == 0 );
2324+ assert ((jl_atomic_load_relaxed (& method -> dispatch_status ) & METHOD_SIG_LATEST_ONLY ) == 0 );
23192325 assert (jl_atomic_load_relaxed (& newentry -> min_world ) == ~(size_t )0 );
23202326 assert (jl_atomic_load_relaxed (& newentry -> max_world ) == 1 );
23212327 jl_atomic_store_relaxed (& newentry -> min_world , world );
@@ -2330,12 +2336,17 @@ void jl_method_table_activate(jl_methtable_t *mt, jl_typemap_entry_t *newentry)
23302336 // then check what entries we replaced
23312337 oldvalue = get_intersect_matches (jl_atomic_load_relaxed (& mt -> defs ), newentry , & replaced , jl_cachearg_offset (mt ), max_world );
23322338 int invalidated = 0 ;
2339+ 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`
23332340 if (replaced ) {
23342341 oldvalue = (jl_value_t * )replaced ;
2342+ jl_method_t * m = replaced -> func .method ;
23352343 invalidated = 1 ;
2336- method_overwrite (newentry , replaced -> func . method );
2344+ method_overwrite (newentry , m );
23372345 // this is an optimized version of below, given we know the type-intersection is exact
2338- jl_method_table_invalidate (mt , replaced -> func .method , max_world );
2346+ jl_method_table_invalidate (mt , m , max_world );
2347+ int m_dispatch = jl_atomic_load_relaxed (& m -> dispatch_status );
2348+ jl_atomic_store_relaxed (& m -> dispatch_status , 0 );
2349+ only = m_dispatch & METHOD_SIG_LATEST_ONLY ;
23392350 }
23402351 else {
23412352 jl_method_t * const * d ;
@@ -2407,8 +2418,10 @@ void jl_method_table_activate(jl_methtable_t *mt, jl_typemap_entry_t *newentry)
24072418 memset (morespec , morespec_unknown , n );
24082419 for (j = 0 ; j < n ; j ++ ) {
24092420 jl_method_t * m = d [j ];
2410- if (morespec [j ] == (char )morespec_is )
2421+ if (morespec [j ] == (char )morespec_is ) {
2422+ only = 0 ;
24112423 continue ;
2424+ }
24122425 loctag = jl_atomic_load_relaxed (& m -> specializations ); // use loctag for a gcroot
24132426 _Atomic(jl_method_instance_t * ) * data ;
24142427 size_t l ;
@@ -2438,7 +2451,7 @@ void jl_method_table_activate(jl_methtable_t *mt, jl_typemap_entry_t *newentry)
24382451 // not actually shadowing--the existing method is still better
24392452 break ;
24402453 if (ambig == morespec_unknown )
2441- ambig = jl_type_morespecific (type , m -> sig ) ? morespec_is : morespec_isnot ;
2454+ ambig = jl_type_morespecific (type , m -> sig ) ? morespec_isnot : morespec_is ;
24422455 // replacing a method--see if this really was the selected method previously
24432456 // over the intersection (not ambiguous) and the new method will be selected now (morespec_is)
24442457 int replaced_dispatch = is_replacing (ambig , type , m , d , n , isect , isect2 , morespec );
@@ -2455,6 +2468,20 @@ void jl_method_table_activate(jl_methtable_t *mt, jl_typemap_entry_t *newentry)
24552468 invalidated |= invalidatedmi ;
24562469 }
24572470 }
2471+ // now compute and store updates to METHOD_SIG_LATEST_ONLY
2472+ int m_dispatch = jl_atomic_load_relaxed (& m -> dispatch_status );
2473+ if (m_dispatch & METHOD_SIG_LATEST_ONLY ) {
2474+ if (morespec [j ] == (char )morespec_unknown )
2475+ morespec [j ] = (char )(jl_type_morespecific (m -> sig , type ) ? morespec_is : morespec_isnot );
2476+ if (morespec [j ] == (char )morespec_isnot )
2477+ jl_atomic_store_relaxed (& m -> dispatch_status , ~METHOD_SIG_LATEST_ONLY & m_dispatch );
2478+ }
2479+ if (only ) {
2480+ if (morespec [j ] == (char )morespec_is || ambig == morespec_is ||
2481+ (ambig == morespec_unknown && !jl_type_morespecific (type , m -> sig ))) {
2482+ only = 0 ;
2483+ }
2484+ }
24582485 }
24592486 if (jl_array_nrows (oldmi )) {
24602487 // search mt->cache and leafcache and drop anything that might overlap with the new method
@@ -2485,7 +2512,8 @@ void jl_method_table_activate(jl_methtable_t *mt, jl_typemap_entry_t *newentry)
24852512 loctag = jl_cstr_to_string ("jl_method_table_insert" );
24862513 jl_array_ptr_1d_push (_jl_debug_method_invalidation , loctag );
24872514 }
2488- jl_atomic_store_relaxed (& newentry -> max_world , jl_atomic_load_relaxed (& method -> deleted_world ));
2515+ jl_atomic_store_relaxed (& newentry -> max_world , ~(size_t )0 );
2516+ 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
24892517 JL_UNLOCK (& mt -> writelock );
24902518 JL_GC_POP ();
24912519}
@@ -2499,7 +2527,6 @@ JL_DLLEXPORT void jl_method_table_insert(jl_methtable_t *mt, jl_method_t *method
24992527 jl_error ("Method changes have been disabled via a call to disable_new_worlds." );
25002528 size_t world = jl_atomic_load_relaxed (& jl_world_counter ) + 1 ;
25012529 jl_atomic_store_relaxed (& method -> primary_world , world );
2502- jl_atomic_store_relaxed (& method -> deleted_world , ~(size_t )0 );
25032530 jl_method_table_activate (mt , newentry );
25042531 jl_atomic_store_release (& jl_world_counter , world );
25052532 JL_UNLOCK (& world_counter_lock );
@@ -3882,6 +3909,8 @@ static int ml_matches_visitor(jl_typemap_entry_t *ml, struct typemap_intersectio
38823909 closure -> match .min_valid = max_world + 1 ;
38833910 return 1 ;
38843911 }
3912+ if (closure -> match .max_valid > max_world )
3913+ closure -> match .max_valid = max_world ;
38853914 jl_method_t * meth = ml -> func .method ;
38863915 if (closure -> lim >= 0 && jl_is_dispatch_tupletype (meth -> sig )) {
38873916 int replaced = 0 ;
@@ -4554,12 +4583,9 @@ static jl_value_t *ml_matches(jl_methtable_t *mt,
45544583 jl_method_t * m = matc -> method ;
45554584 // method applicability is the same as typemapentry applicability
45564585 size_t min_world = jl_atomic_load_relaxed (& m -> primary_world );
4557- size_t max_world = jl_atomic_load_relaxed (& m -> deleted_world );
45584586 // intersect the env valid range with method lookup's inclusive valid range
45594587 if (env .match .min_valid < min_world )
45604588 env .match .min_valid = min_world ;
4561- if (env .match .max_valid > max_world )
4562- env .match .max_valid = max_world ;
45634589 }
45644590 if (mt && cache_result && ((jl_datatype_t * )unw )-> isdispatchtuple ) { // cache_result parameter keeps this from being recursive
45654591 if (len == 1 && !has_ambiguity ) {
0 commit comments