@@ -296,7 +296,7 @@ void jl_mk_builtin_func(jl_datatype_t *dt, jl_sym_t *sname, jl_fptr_args_t fptr)
296
296
m -> isva = 1 ;
297
297
m -> nargs = 2 ;
298
298
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 );
300
300
m -> sig = (jl_value_t * )jl_anytuple_type ;
301
301
m -> slot_syms = jl_an_empty_string ;
302
302
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)
307
307
JL_GC_PUSH2 (& m , & newentry );
308
308
309
309
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 );
311
311
jl_typemap_insert (& mt -> defs , (jl_value_t * )mt , newentry , jl_cachearg_offset (mt ));
312
312
313
313
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_
1908
1908
// since m2 was also a previous match over isect,
1909
1909
// see if m was previously dominant over all m2
1910
1910
// 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 )) {
1912
1912
// m and m2 were previously ambiguous over the full intersection of mi with type, and will still be ambiguous with addition of type
1913
1913
return 0 ;
1914
1914
}
@@ -2242,17 +2242,22 @@ JL_DLLEXPORT void jl_method_table_disable(jl_methtable_t *mt, jl_method_t *metho
2242
2242
JL_LOCK (& world_counter_lock );
2243
2243
if (!jl_atomic_load_relaxed (& allow_new_worlds ))
2244
2244
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
+ }
2255
2258
JL_UNLOCK (& world_counter_lock );
2259
+ if (!enabled )
2260
+ jl_errorf ("Method of %s already disabled" , jl_symbol_name (method -> name ));
2256
2261
}
2257
2262
2258
2263
static 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,
2292
2297
JL_LOCK (& mt -> writelock );
2293
2298
// add our new entry
2294
2299
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 );
2298
2303
jl_typemap_insert (& mt -> defs , (jl_value_t * )mt , newentry , jl_cachearg_offset (mt ));
2299
2304
update_max_args (mt , method -> sig );
2300
2305
JL_UNLOCK (& mt -> writelock );
@@ -2315,7 +2320,8 @@ void jl_method_table_activate(jl_methtable_t *mt, jl_typemap_entry_t *newentry)
2315
2320
JL_LOCK (& mt -> writelock );
2316
2321
size_t world = jl_atomic_load_relaxed (& method -> primary_world );
2317
2322
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 );
2319
2325
assert (jl_atomic_load_relaxed (& newentry -> min_world ) == ~(size_t )0 );
2320
2326
assert (jl_atomic_load_relaxed (& newentry -> max_world ) == 1 );
2321
2327
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)
2330
2336
// then check what entries we replaced
2331
2337
oldvalue = get_intersect_matches (jl_atomic_load_relaxed (& mt -> defs ), newentry , & replaced , jl_cachearg_offset (mt ), max_world );
2332
2338
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`
2333
2340
if (replaced ) {
2334
2341
oldvalue = (jl_value_t * )replaced ;
2342
+ jl_method_t * m = replaced -> func .method ;
2335
2343
invalidated = 1 ;
2336
- method_overwrite (newentry , replaced -> func . method );
2344
+ method_overwrite (newentry , m );
2337
2345
// 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 ;
2339
2350
}
2340
2351
else {
2341
2352
jl_method_t * const * d ;
@@ -2407,8 +2418,10 @@ void jl_method_table_activate(jl_methtable_t *mt, jl_typemap_entry_t *newentry)
2407
2418
memset (morespec , morespec_unknown , n );
2408
2419
for (j = 0 ; j < n ; j ++ ) {
2409
2420
jl_method_t * m = d [j ];
2410
- if (morespec [j ] == (char )morespec_is )
2421
+ if (morespec [j ] == (char )morespec_is ) {
2422
+ only = 0 ;
2411
2423
continue ;
2424
+ }
2412
2425
loctag = jl_atomic_load_relaxed (& m -> specializations ); // use loctag for a gcroot
2413
2426
_Atomic(jl_method_instance_t * ) * data ;
2414
2427
size_t l ;
@@ -2438,7 +2451,7 @@ void jl_method_table_activate(jl_methtable_t *mt, jl_typemap_entry_t *newentry)
2438
2451
// not actually shadowing--the existing method is still better
2439
2452
break ;
2440
2453
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 ;
2442
2455
// replacing a method--see if this really was the selected method previously
2443
2456
// over the intersection (not ambiguous) and the new method will be selected now (morespec_is)
2444
2457
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)
2455
2468
invalidated |= invalidatedmi ;
2456
2469
}
2457
2470
}
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
+ }
2458
2485
}
2459
2486
if (jl_array_nrows (oldmi )) {
2460
2487
// 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)
2485
2512
loctag = jl_cstr_to_string ("jl_method_table_insert" );
2486
2513
jl_array_ptr_1d_push (_jl_debug_method_invalidation , loctag );
2487
2514
}
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
2489
2517
JL_UNLOCK (& mt -> writelock );
2490
2518
JL_GC_POP ();
2491
2519
}
@@ -2499,7 +2527,6 @@ JL_DLLEXPORT void jl_method_table_insert(jl_methtable_t *mt, jl_method_t *method
2499
2527
jl_error ("Method changes have been disabled via a call to disable_new_worlds." );
2500
2528
size_t world = jl_atomic_load_relaxed (& jl_world_counter ) + 1 ;
2501
2529
jl_atomic_store_relaxed (& method -> primary_world , world );
2502
- jl_atomic_store_relaxed (& method -> deleted_world , ~(size_t )0 );
2503
2530
jl_method_table_activate (mt , newentry );
2504
2531
jl_atomic_store_release (& jl_world_counter , world );
2505
2532
JL_UNLOCK (& world_counter_lock );
@@ -3882,6 +3909,8 @@ static int ml_matches_visitor(jl_typemap_entry_t *ml, struct typemap_intersectio
3882
3909
closure -> match .min_valid = max_world + 1 ;
3883
3910
return 1 ;
3884
3911
}
3912
+ if (closure -> match .max_valid > max_world )
3913
+ closure -> match .max_valid = max_world ;
3885
3914
jl_method_t * meth = ml -> func .method ;
3886
3915
if (closure -> lim >= 0 && jl_is_dispatch_tupletype (meth -> sig )) {
3887
3916
int replaced = 0 ;
@@ -4554,12 +4583,9 @@ static jl_value_t *ml_matches(jl_methtable_t *mt,
4554
4583
jl_method_t * m = matc -> method ;
4555
4584
// method applicability is the same as typemapentry applicability
4556
4585
size_t min_world = jl_atomic_load_relaxed (& m -> primary_world );
4557
- size_t max_world = jl_atomic_load_relaxed (& m -> deleted_world );
4558
4586
// intersect the env valid range with method lookup's inclusive valid range
4559
4587
if (env .match .min_valid < min_world )
4560
4588
env .match .min_valid = min_world ;
4561
- if (env .match .max_valid > max_world )
4562
- env .match .max_valid = max_world ;
4563
4589
}
4564
4590
if (mt && cache_result && ((jl_datatype_t * )unw )-> isdispatchtuple ) { // cache_result parameter keeps this from being recursive
4565
4591
if (len == 1 && !has_ambiguity ) {
0 commit comments