diff --git a/src/gf.c b/src/gf.c index 2e8b5c672c4b2..f0b91e6dd8fdb 100644 --- a/src/gf.c +++ b/src/gf.c @@ -951,13 +951,34 @@ JL_DLLEXPORT int jl_isa_compileable_sig( return 1; } + +static int concretesig_equal(jl_value_t *tt, jl_value_t *simplesig) JL_NOTSAFEPOINT +{ + jl_value_t **types = jl_svec_data(((jl_datatype_t*)tt)->parameters); + jl_value_t **sigs = jl_svec_data(((jl_datatype_t*)simplesig)->parameters); + size_t i, lensig = jl_nparams(simplesig); + assert(lensig == jl_nparams(tt)); + assert(lensig > 0 && !jl_is_vararg_type(jl_tparam(simplesig, lensig - 1))); + for (i = 0; i < lensig; i++) { + jl_value_t *decl = sigs[i]; + jl_value_t *a = types[i]; + if (a != decl && decl != (jl_value_t*)jl_any_type) { + if (!(jl_is_type_type(a) && jl_typeof(jl_tparam0(a)) == decl)) + return 0; + } + } + return 1; +} + static inline jl_typemap_entry_t *lookup_leafcache(jl_array_t *leafcache JL_PROPAGATES_ROOT, jl_value_t *tt, size_t world) JL_NOTSAFEPOINT { jl_typemap_entry_t *entry = (jl_typemap_entry_t*)jl_eqtable_get(leafcache, (jl_value_t*)tt, NULL); if (entry) { do { - if (entry->min_world <= world && world <= entry->max_world) - return entry; + if (entry->min_world <= world && world <= entry->max_world) { + if (entry->simplesig == (void*)jl_nothing || concretesig_equal(tt, (jl_value_t*)entry->simplesig)) + return entry; + } entry = entry->next; } while ((jl_value_t*)entry != jl_nothing); } @@ -1118,7 +1139,7 @@ static jl_method_instance_t *cache_method( jl_typemap_entry_t *newentry = jl_typemap_alloc(cachett, simplett, guardsigs, (jl_value_t*)newmeth, min_valid, max_valid); temp = (jl_value_t*)newentry; - if (mt && cachett == tt && simplett == NULL && jl_svec_len(guardsigs) == 0) { + if (mt && cachett == tt && jl_svec_len(guardsigs) == 0) { if (!jl_has_free_typevars((jl_value_t*)tt) && jl_lookup_cache_type_(tt) == NULL) { // if this type isn't normally in the cache, force it in there now // anyways so that we can depend on it as a token (especially since @@ -1729,9 +1750,13 @@ JL_DLLEXPORT void jl_method_table_disable(jl_methtable_t *mt, jl_method_t *metho jl_array_t *leafcache = mt->leafcache; size_t i, l = jl_array_len(leafcache); for (i = 1; i < l; i += 2) { - jl_value_t *l = jl_array_ptr_ref(leafcache, i); - if (l && l != jl_nothing) - invalidate_mt_cache((jl_typemap_entry_t*)l, (void*)&mt_cache_env); + jl_typemap_entry_t *oldentry = (jl_typemap_entry_t*)jl_array_ptr_ref(leafcache, i); + if (oldentry) { + while ((jl_value_t*)oldentry != jl_nothing) { + invalidate_mt_cache(oldentry, (void*)&mt_cache_env); + oldentry = oldentry->next; + } + } } // Invalidate the backedges int invalidated = 0; @@ -1828,9 +1853,13 @@ JL_DLLEXPORT void jl_method_table_insert(jl_methtable_t *mt, jl_method_t *method jl_array_t *leafcache = mt->leafcache; size_t i, l = jl_array_len(leafcache); for (i = 1; i < l; i += 2) { - jl_value_t *l = jl_array_ptr_ref(leafcache, i); - if (l && l != jl_nothing) - invalidate_mt_cache((jl_typemap_entry_t*)l, (void*)&mt_cache_env); + jl_value_t *entry = jl_array_ptr_ref(leafcache, i); + if (entry) { + while (entry != jl_nothing) { + invalidate_mt_cache((jl_typemap_entry_t*)entry, (void*)&mt_cache_env); + entry = (jl_value_t*)((jl_typemap_entry_t*)entry)->next; + } + } } //TODO: if it's small, might it be better to drop it all? //if (mt != jl_type_type_mt) { @@ -2884,18 +2913,23 @@ static jl_value_t *ml_matches(jl_methtable_t *mt, int offs, struct jl_typemap_assoc search = {(jl_value_t*)type, world, jl_emptysvec, 1, ~(size_t)0}; JL_GC_PUSH5(&env.t, &env.matc, &env.match.env, &search.env, &env.match.ti); + // check the leaf cache if this type can be in there if (((jl_datatype_t*)unw)->isdispatchtuple) { jl_array_t *leafcache = jl_atomic_load_relaxed(&mt->leafcache); jl_typemap_entry_t *entry = lookup_leafcache(leafcache, (jl_value_t*)type, world); if (entry) { jl_method_instance_t *mi = entry->func.linfo; jl_method_t *meth = mi->def.method; - if (jl_egal((jl_value_t*)type, mi->specTypes)) { + if (!jl_is_unionall(meth->sig)) { + env.match.env = jl_emptysvec; + env.match.ti = unw; + } + else if (jl_egal((jl_value_t*)type, mi->specTypes)) { env.match.env = mi->sparam_vals; env.match.ti = mi->specTypes; } else { - // TODO: should we use jl_subtype_env instead (since we know that `type <: meth->sig` by transitivity) + // this just calls jl_subtype_env (since we know that `type <: meth->sig` by transitivity) env.match.ti = jl_type_intersection_env((jl_value_t*)type, (jl_value_t*)meth->sig, &env.match.env); } env.matc = jl_svec(3, env.match.ti, env.match.env, meth); @@ -2909,13 +2943,20 @@ static jl_value_t *ml_matches(jl_methtable_t *mt, int offs, return env.t; } } + // then check the full cache if it seems profitable if (((jl_datatype_t*)unw)->isdispatchtuple) { jl_typemap_entry_t *entry = jl_typemap_assoc_by_type(mt->cache, &search, jl_cachearg_offset(mt), /*subtype*/1); if (entry && (((jl_datatype_t*)unw)->isdispatchtuple || entry->guardsigs == jl_emptysvec)) { jl_method_instance_t *mi = entry->func.linfo; jl_method_t *meth = mi->def.method; - // TODO: should we use jl_subtype_env instead (since we know that `type <: meth->sig` by transitivity) - env.match.ti = jl_type_intersection_env((jl_value_t*)type, (jl_value_t*)meth->sig, &env.match.env); + if (!jl_is_unionall(meth->sig) && ((jl_datatype_t*)unw)->isdispatchtuple) { + env.match.env = jl_emptysvec; + env.match.ti = unw; + } + else { + // this just calls jl_subtype_env (since we know that `type <: meth->sig` by transitivity) + env.match.ti = jl_type_intersection_env((jl_value_t*)type, (jl_value_t*)meth->sig, &env.match.env); + } env.matc = jl_svec(3, env.match.ti, env.match.env, meth); env.t = (jl_value_t*)jl_alloc_vec_any(1); jl_array_ptr_set(env.t, 0, env.matc); diff --git a/src/jltypes.c b/src/jltypes.c index 23cff09e68bb6..c7d5922a1d850 100644 --- a/src/jltypes.c +++ b/src/jltypes.c @@ -689,7 +689,7 @@ static ssize_t lookup_type_idx_linearvalue(jl_svec_t *cache, jl_value_t *key1, j size_t cl = jl_svec_len(cache); ssize_t i; for (i = 0; i < cl; i++) { - jl_datatype_t *tt = jl_atomic_load_relaxed(&data[i - 1]); + jl_datatype_t *tt = jl_atomic_load_relaxed(&data[i]); if (tt == NULL) return ~i; if (typekeyvalue_eq(tt, key1, key, n, 1))