diff --git a/base/reflection.jl b/base/reflection.jl index a8ed7cbfe3bb6..11764074c159b 100644 --- a/base/reflection.jl +++ b/base/reflection.jl @@ -276,6 +276,7 @@ function visit(f, mc::TypeMapLevel) end end mc.list !== nothing && visit(f, mc.list) + mc.any !== nothing && visit(f, mc.any) nothing end function visit(f, d::TypeMapEntry) diff --git a/src/dump.c b/src/dump.c index 97ed96080ebad..c2b1b899cd3dd 100644 --- a/src/dump.c +++ b/src/dump.c @@ -933,8 +933,9 @@ static void jl_serialize_value_(ios_t *s, jl_value_t *v) offsetof(jl_typemap_level_t, arg1) == 0 * sizeof(jl_value_t*) && offsetof(jl_typemap_level_t, targ) == 1 * sizeof(jl_value_t*) && offsetof(jl_typemap_level_t, linear) == 2 * sizeof(jl_value_t*) && - offsetof(jl_typemap_level_t, key) == 3 * sizeof(jl_value_t*) && - sizeof(jl_typemap_level_t) == 4 * sizeof(jl_value_t*)); + offsetof(jl_typemap_level_t, any) == 3 * sizeof(jl_value_t*) && + offsetof(jl_typemap_level_t, key) == 4 * sizeof(jl_value_t*) && + sizeof(jl_typemap_level_t) == 5 * sizeof(jl_value_t*)); if (node->arg1 != (void*)jl_nothing) { jl_array_t *a = jl_alloc_cell_1d(0); for (i = 0, l = jl_array_len(node->arg1); i < l; i++) { @@ -960,6 +961,7 @@ static void jl_serialize_value_(ios_t *s, jl_value_t *v) jl_serialize_value(s, jl_nothing); } jl_serialize_value(s, node->linear); + jl_serialize_value(s, node->any.unknown); jl_serialize_value(s, node->key); return; } diff --git a/src/jltypes.c b/src/jltypes.c index 3d5fc7f09bdd8..6231ba789a59a 100644 --- a/src/jltypes.c +++ b/src/jltypes.c @@ -3386,9 +3386,9 @@ void jl_init_types(void) jl_typemap_level_type = jl_new_datatype(jl_symbol("TypeMapLevel"), jl_any_type, jl_emptysvec, - jl_svec(4, jl_symbol("arg1"), jl_symbol("targ"), jl_symbol("list"), jl_symbol("key")), - jl_svec(4, jl_any_type, jl_any_type, jl_any_type, jl_any_type), - 0, 1, 3); + jl_svec(5, jl_symbol("arg1"), jl_symbol("targ"), jl_symbol("list"), jl_symbol("any"), jl_symbol("key")), + jl_svec(5, jl_any_type, jl_any_type, jl_any_type, jl_any_type, jl_any_type), + 0, 1, 4); jl_typemap_entry_type = jl_new_datatype(jl_symbol("TypeMapEntry"), jl_any_type, jl_emptysvec, diff --git a/src/julia.h b/src/julia.h index d9a191706c100..0099d204fc06d 100644 --- a/src/julia.h +++ b/src/julia.h @@ -409,6 +409,7 @@ typedef struct _jl_typemap_level_t { jl_array_t *arg1; // Array{union jl_typemap_t} jl_array_t *targ; // Array{union jl_typemap_t} jl_typemap_entry_t *linear; // union jl_typemap_t (but no more levels) + union jl_typemap_t any; // type at offs is Any jl_value_t *key; // [nullable] } jl_typemap_level_t; diff --git a/src/typemap.c b/src/typemap.c index 7a61edf6486d3..d9587a5a47401 100644 --- a/src/typemap.c +++ b/src/typemap.c @@ -16,6 +16,14 @@ extern "C" { #endif +static int jl_is_any(jl_value_t *t1) +{ + return (t1 == (jl_value_t*)jl_any_type || + (jl_is_typevar(t1) && + ((jl_tvar_t*)t1)->ub == (jl_value_t*)jl_any_type && + !((jl_tvar_t*)t1)->bound)); +} + // ----- Type Signature Subtype Testing ----- // static int sig_match_by_type_leaf(jl_value_t **types, jl_tupletype_t *sig, size_t n) @@ -245,6 +253,7 @@ void jl_typemap_rehash(union jl_typemap_t ml, int8_t offs) { jl_typemap_rehash_array(&ml.node->targ, ml.unknown, 1, offs); if (ml.node->arg1 != (void*)jl_nothing) jl_typemap_rehash_array(&ml.node->arg1, ml.unknown, 0, offs); + jl_typemap_rehash(ml.node->any, offs+1); } } @@ -331,25 +340,32 @@ static int jl_typemap_array_visitor(jl_array_t *a, jl_typemap_visitor_fptr fptr, } // calls fptr on each jl_typemap_entry_t in cache in sort order, until fptr return false +static int jl_typemap_node_visitor(jl_typemap_entry_t *ml, jl_typemap_visitor_fptr fptr, void *closure) +{ + while (ml != (void*)jl_nothing) { + if (!fptr(ml, closure)) + return 0; + ml = ml->next; + } + return 1; +} + int jl_typemap_visitor(union jl_typemap_t cache, jl_typemap_visitor_fptr fptr, void *closure) { - jl_typemap_entry_t *ml; if (jl_typeof(cache.unknown) == (jl_value_t*)jl_typemap_level_type) { if (cache.node->targ != (void*)jl_nothing) - if (!jl_typemap_array_visitor(cache.node->targ, fptr, closure)) return 0; + if (!jl_typemap_array_visitor(cache.node->targ, fptr, closure)) + return 0; if (cache.node->arg1 != (void*)jl_nothing) - if (!jl_typemap_array_visitor(cache.node->arg1, fptr, closure)) return 0; - ml = cache.node->linear; + if (!jl_typemap_array_visitor(cache.node->arg1, fptr, closure)) + return 0; + if (!jl_typemap_node_visitor(cache.node->linear, fptr, closure)) + return 0; + return jl_typemap_visitor(cache.node->any, fptr, closure); } else { - ml = cache.leaf; - } - while (ml != (void*)jl_nothing) { - if (!fptr(ml, closure)) - return 0; - ml = ml->next; + return jl_typemap_node_visitor(cache.leaf, fptr, closure); } - return 1; } // predicate to fast-test if this type is a leaf type that can exist in the cache @@ -386,10 +402,45 @@ static int jl_typemap_intersection_array_visitor(jl_array_t *a, jl_value_t *ty, // calls fptr on each jl_typemap_entry_t in cache in sort order // for which type ∩ ml->type != Union{}, until fptr return false +static int jl_typemap_intersection_node_visitor(jl_typemap_entry_t *ml, struct typemap_intersection_env *closure) +{ + // slow-path scan everything in ml + // mark this `register` because (for branch prediction) + // that can be absolutely critical for speed + register jl_typemap_intersection_visitor_fptr fptr = closure->fptr; + while (ml != (void*)jl_nothing) { + // TODO: optimize intersection test + if (closure->type == (jl_value_t*)ml->sig) { + // fast-path for the intersection of a type with itself + if (closure->env) + closure->env = ml->tvars; + closure->ti = closure->type; + if (!fptr(ml, closure)) + return 0; + } + else { + jl_value_t *ti; + if (closure->env) { + closure->env = jl_emptysvec; + ti = jl_lookup_match(closure->type, (jl_value_t*)ml->sig, &closure->env, ml->tvars); + } + else { + ti = jl_type_intersection(closure->type, (jl_value_t*)ml->sig); + } + if (ti != (jl_value_t*)jl_bottom_type) { + closure->ti = ti; + if (!fptr(ml, closure)) + return 0; + } + } + ml = ml->next; + } + return 1; +} + int jl_typemap_intersection_visitor(union jl_typemap_t map, int offs, struct typemap_intersection_env *closure) { - jl_typemap_entry_t *ml; if (jl_typeof(map.unknown) == (jl_value_t*)jl_typemap_level_type) { jl_typemap_level_t *cache = map.node; jl_value_t *ty = NULL; @@ -429,43 +480,13 @@ int jl_typemap_intersection_visitor(union jl_typemap_t map, int offs, } } } - ml = map.node->linear; + if (!jl_typemap_intersection_node_visitor(map.node->linear, closure)) + return 0; + return jl_typemap_intersection_visitor(map.node->any, offs+1, closure); } else { - ml = map.leaf; - } - // slow-path scan everything else - // mark this `register` because (for branch prediction) - // that can be absolutely critical for speed - register jl_typemap_intersection_visitor_fptr fptr = closure->fptr; - while (ml != (void*)jl_nothing) { - // TODO: optimize intersection test - if (closure->type == (jl_value_t*)ml->sig) { - // fast-path for the intersection of a type with itself - if (closure->env) - closure->env = ml->tvars; - closure->ti = closure->type; - if (!fptr(ml, closure)) - return 0; - } - else { - jl_value_t *ti; - if (closure->env) { - closure->env = jl_emptysvec; - ti = jl_lookup_match(closure->type, (jl_value_t*)ml->sig, &closure->env, ml->tvars); - } - else { - ti = jl_type_intersection(closure->type, (jl_value_t*)ml->sig); - } - if (ti != (jl_value_t*)jl_bottom_type) { - closure->ti = ti; - if (!fptr(ml, closure)) - return 0; - } - } - ml = ml->next; + return jl_typemap_intersection_node_visitor(map.leaf, closure); } - return 1; } int sigs_eq(jl_value_t *a, jl_value_t *b, int useenv) @@ -585,12 +606,12 @@ static jl_typemap_entry_t *jl_typemap_lookup_by_type_(jl_typemap_entry_t *ml, jl jl_typemap_entry_t *jl_typemap_assoc_by_type(union jl_typemap_t ml_or_cache, jl_tupletype_t *types, jl_svec_t **penv, int8_t subtype_inexact__sigseq_useenv, int8_t subtype, int8_t offs) { - jl_typemap_entry_t *ml; if (jl_typeof(ml_or_cache.unknown) == (jl_value_t*)jl_typemap_level_type) { jl_typemap_level_t *cache = ml_or_cache.node; // called object is the primary key for constructors, otherwise first argument + jl_value_t *ty = NULL; if (jl_datatype_nfields(types) > offs) { - jl_value_t *ty = jl_tparam(types, offs); + ty = jl_tparam(types, offs); if (cache->targ != (void*)jl_nothing && jl_is_type_type(ty)) { jl_value_t *a0 = jl_tparam0(ty); if (jl_is_datatype(a0)) { @@ -598,8 +619,7 @@ jl_typemap_entry_t *jl_typemap_assoc_by_type(union jl_typemap_t ml_or_cache, jl_ if (ml.unknown != jl_nothing) { jl_typemap_entry_t *li = jl_typemap_assoc_by_type(ml, types, penv, subtype_inexact__sigseq_useenv, subtype, offs+1); - if (li) - return li; + if (li) return li; } } } @@ -608,25 +628,68 @@ jl_typemap_entry_t *jl_typemap_assoc_by_type(union jl_typemap_t ml_or_cache, jl_ if (ml.unknown != jl_nothing) { jl_typemap_entry_t *li = jl_typemap_assoc_by_type(ml, types, penv, subtype_inexact__sigseq_useenv, subtype, offs+1); - if (li) - return li; + if (li) return li; } } } - ml = cache->linear; + if (subtype) { + jl_typemap_entry_t *li = jl_typemap_assoc_by_type_(cache->linear, types, subtype_inexact__sigseq_useenv, penv); + if (li) return li; + return jl_typemap_assoc_by_type(cache->any, types, penv, subtype_inexact__sigseq_useenv, subtype, offs+1); + } + else { + if (ty && jl_is_any(ty)) + return jl_typemap_assoc_by_type(cache->any, types, penv, subtype_inexact__sigseq_useenv, subtype, offs+1); + else + return jl_typemap_lookup_by_type_(cache->linear, types, subtype_inexact__sigseq_useenv); + } } else { - ml = ml_or_cache.leaf; + return subtype ? + jl_typemap_assoc_by_type_(ml_or_cache.leaf, types, subtype_inexact__sigseq_useenv, penv) : + jl_typemap_lookup_by_type_(ml_or_cache.leaf, types, subtype_inexact__sigseq_useenv); } - return subtype ? - jl_typemap_assoc_by_type_(ml, types, subtype_inexact__sigseq_useenv, penv) : - jl_typemap_lookup_by_type_(ml, types, subtype_inexact__sigseq_useenv); +} + +static jl_typemap_entry_t *jl_typemap_node_assoc_exact(jl_typemap_entry_t *ml, jl_value_t **args, size_t n) +{ + while (ml != (void*)jl_nothing) { + size_t lensig = jl_datatype_nfields(ml->sig); + if (lensig == n || (ml->va && lensig <= n+1)) { + int ismatch; + if (ml->simplesig != (void*)jl_nothing && + !sig_match_simple(args, n, jl_svec_data(ml->simplesig->parameters), 0, + jl_datatype_nfields(ml->simplesig))) + ismatch = 0; + else if (ml->isleafsig) + ismatch = sig_match_leaf(args, jl_svec_data(ml->sig->parameters), n); + else if (ml->issimplesig) + ismatch = sig_match_simple(args, n, jl_svec_data(ml->sig->parameters), ml->va, lensig); + else + ismatch = jl_tuple_subtype(args, n, ml->sig, 1); + + if (ismatch) { + size_t i, l; + for (i = 0, l = jl_svec_len(ml->guardsigs); i < l; i++) { + // checking guard entries require a more + // expensive subtype check, since guard entries added for ANY might be + // abstract. this fixed issue #12967. + if (jl_tuple_subtype(args, n, (jl_tupletype_t*)jl_svecref(ml->guardsigs, i), 1)) { + break; + } + } + if (i == l) + return ml; + } + } + ml = ml->next; + } + return NULL; } jl_typemap_entry_t *jl_typemap_assoc_exact(union jl_typemap_t ml_or_cache, jl_value_t **args, size_t n, int8_t offs) { // NOTE: This function is a huge performance hot spot!! - jl_typemap_entry_t *ml; if (jl_typeof(ml_or_cache.unknown) == (jl_value_t*)jl_typemap_level_type) { jl_typemap_level_t *cache = ml_or_cache.node; if (n > offs) { @@ -635,9 +698,8 @@ jl_typemap_entry_t *jl_typemap_assoc_exact(union jl_typemap_t ml_or_cache, jl_va assert(jl_is_datatype(ty)); if (ty == (jl_value_t*)jl_datatype_type && cache->targ != (void*)jl_nothing) { ml_or_cache = mtcache_hash_lookup(cache->targ, a1, 1, offs); - ml = jl_typemap_assoc_exact(ml_or_cache, args, n, offs+1); - if (ml) - return ml; + jl_typemap_entry_t *ml = jl_typemap_assoc_exact(ml_or_cache, args, n, offs+1); + if (ml) return ml; } if (cache->arg1 != (void*)jl_nothing) { ml_or_cache = mtcache_hash_lookup(cache->arg1, ty, 0, offs); @@ -665,51 +727,21 @@ jl_typemap_entry_t *jl_typemap_assoc_exact(union jl_typemap_t ml_or_cache, jl_va } } } - ml = jl_typemap_assoc_exact(ml_or_cache, args, n, offs+1); - if (ml) - return ml; + jl_typemap_entry_t *ml = jl_typemap_assoc_exact(ml_or_cache, args, n, offs+1); + if (ml) return ml; } } - ml = cache->linear; + jl_typemap_entry_t *ml = jl_typemap_node_assoc_exact(cache->linear, args, n); + if (ml) return ml; + return jl_typemap_assoc_exact(cache->any, args, n, offs+1); } else { - ml = ml_or_cache.leaf; - } - while (ml != (void*)jl_nothing) { - size_t lensig = jl_datatype_nfields(ml->sig); - if (lensig == n || (ml->va && lensig <= n+1)) { - int ismatch; - if (ml->simplesig != (void*)jl_nothing && - !sig_match_simple(args, n, jl_svec_data(ml->simplesig->parameters), 0, - jl_datatype_nfields(ml->simplesig))) - ismatch = 0; - else if (ml->isleafsig) - ismatch = sig_match_leaf(args, jl_svec_data(ml->sig->parameters), n); - else if (ml->issimplesig) - ismatch = sig_match_simple(args, n, jl_svec_data(ml->sig->parameters), ml->va, lensig); - else - ismatch = jl_tuple_subtype(args, n, ml->sig, 1); - - if (ismatch) { - size_t i, l; - for (i = 0, l = jl_svec_len(ml->guardsigs); i < l; i++) { - // checking guard entries require a more - // expensive subtype check, since guard entries added for ANY might be - // abstract. this fixed issue #12967. - if (jl_tuple_subtype(args, n, (jl_tupletype_t*)jl_svecref(ml->guardsigs, i), 1)) { - break; - } - } - if (i == l) - return ml; - } - } - ml = ml->next; + return jl_typemap_node_assoc_exact(ml_or_cache.leaf, args, n); } - return NULL; } + // ----- Method List Insertion Management ----- // static unsigned jl_typemap_list_count(jl_typemap_entry_t *ml) @@ -732,6 +764,7 @@ static jl_typemap_level_t *jl_new_typemap_level(void) jl_set_typeof(cache, jl_typemap_level_type); cache->key = NULL; cache->linear = (jl_typemap_entry_t*)jl_nothing; + cache->any.unknown = jl_nothing; cache->arg1 = (jl_array_t*)jl_nothing; cache->targ = (jl_array_t*)jl_nothing; return cache; @@ -813,6 +846,8 @@ static void jl_typemap_level_insert_(jl_typemap_level_t *cache, jl_typemap_entry } if (jl_typemap_array_insert_(&cache->arg1, t1, newrec, (jl_value_t*)cache, 0, offs, tparams)) return; + if (jl_is_any(t1)) + return jl_typemap_insert_generic(&cache->any, (jl_value_t*)cache, newrec, (jl_value_t*)jl_any_type, offs+1, tparams); } jl_typemap_list_insert_(&cache->linear, (jl_value_t*)cache, newrec, tparams); }