diff --git a/base/reflection.jl b/base/reflection.jl index 9e1e27a517d96..bd4b8303f7ed5 100644 --- a/base/reflection.jl +++ b/base/reflection.jl @@ -289,6 +289,7 @@ function visit(f, mt::MethodTable) nothing end function visit(f, mc::TypeMapLevel) + mc.bottom !== nothing && visit(f, mc.bottom) if mc.targ !== nothing e = mc.targ::Vector{Any} for i in 1:length(e) @@ -301,6 +302,18 @@ function visit(f, mc::TypeMapLevel) isdefined(e, i) && visit(f, e[i]) end end + if mc.tname !== nothing + e = mc.tname::Vector{Any} + for i in 1:length(e) + isdefined(e, i) && visit(f, e[i]) + end + end + if mc.name1 !== nothing + e = mc.name1::Vector{Any} + for i in 1:length(e) + isdefined(e, i) && visit(f, e[i]) + end + end mc.list !== nothing && visit(f, mc.list) mc.any !== nothing && visit(f, mc.any) nothing diff --git a/src/dump.c b/src/dump.c index 4780a126f3b0a..ffaa703c8cbf3 100644 --- a/src/dump.c +++ b/src/dump.c @@ -939,16 +939,24 @@ static void jl_serialize_value_(ios_t *s, jl_value_t *v) // (which will need to be rehashed during deserialization anyhow) jl_typemap_level_t *node = (jl_typemap_level_t*)v; assert( // make sure this type has the expected ordering - offsetof(jl_typemap_level_t, arg1) == 0 * sizeof(jl_value_t*) && - offsetof(jl_typemap_level_t, targ) == 2 * sizeof(jl_value_t*) && - offsetof(jl_typemap_level_t, linear) == 4 * sizeof(jl_value_t*) && - offsetof(jl_typemap_level_t, any) == 5 * sizeof(jl_value_t*) && - offsetof(jl_typemap_level_t, key) == 6 * sizeof(jl_value_t*) && - sizeof(jl_typemap_level_t) == 7 * sizeof(jl_value_t*)); + offsetof(jl_typemap_level_t, bottom) == 0 * sizeof(jl_value_t*) && + offsetof(jl_typemap_level_t, targ) == 1 * sizeof(jl_value_t*) && + offsetof(jl_typemap_level_t, arg1) == 3 * sizeof(jl_value_t*) && + offsetof(jl_typemap_level_t, tname) == 5 * sizeof(jl_value_t*) && + offsetof(jl_typemap_level_t, name1) == 7 * sizeof(jl_value_t*) && + offsetof(jl_typemap_level_t, linear) == 9 * sizeof(jl_value_t*) && + offsetof(jl_typemap_level_t, any) == 10 * sizeof(jl_value_t*) && + offsetof(jl_typemap_level_t, key) == 11 * sizeof(jl_value_t*) && + sizeof(jl_typemap_level_t) == 12 * sizeof(jl_value_t*)); + jl_serialize_value(s, node->bottom); + jl_serialize_value(s, jl_nothing); + jl_serialize_value(s, node->targ.values); jl_serialize_value(s, jl_nothing); jl_serialize_value(s, node->arg1.values); jl_serialize_value(s, jl_nothing); - jl_serialize_value(s, node->targ.values); + jl_serialize_value(s, node->tname.values); + jl_serialize_value(s, jl_nothing); + jl_serialize_value(s, node->name1.values); jl_serialize_value(s, node->linear); jl_serialize_value(s, node->any.unknown); jl_serialize_value(s, node->key); @@ -987,7 +995,7 @@ struct jl_serialize_methcache_from_mod_env { static int jl_serialize_methcache_from_mod(jl_typemap_entry_t *ml, void *closure) { struct jl_serialize_methcache_from_mod_env *env = (struct jl_serialize_methcache_from_mod_env*)closure; - if (module_in_worklist(ml->func.method->module)) { + if (module_in_worklist(ml->func.method->module) && !ml->weak) { jl_serialize_value(env->s, ml->func.method); jl_serialize_value(env->s, ml->simplesig); } diff --git a/src/jltypes.c b/src/jltypes.c index c3975601a4b15..4a7d19f34b34f 100644 --- a/src/jltypes.c +++ b/src/jltypes.c @@ -3678,15 +3678,25 @@ void jl_init_types(void) jl_typemap_level_type = jl_new_datatype(jl_symbol("TypeMapLevel"), jl_any_type, jl_emptysvec, - jl_svec(7, - jl_symbol("index_arg1"), - jl_symbol("arg1"), + jl_svec(12, + jl_symbol("bottom"), jl_symbol("index_targ"), jl_symbol("targ"), + jl_symbol("index_arg1"), + jl_symbol("arg1"), + jl_symbol("index_tname"), + jl_symbol("tname"), + jl_symbol("index_name1"), + jl_symbol("name1"), jl_symbol("list"), jl_symbol("any"), jl_symbol("key")), - jl_svec(7, + jl_svec(12, + jl_any_type, + jl_any_type, + jl_any_type, + jl_any_type, + jl_any_type, jl_any_type, jl_any_type, jl_any_type, @@ -3694,11 +3704,11 @@ void jl_init_types(void) jl_any_type, jl_any_type, jl_any_type), - 0, 1, 6); + 0, 1, 11); jl_typemap_entry_type = jl_new_datatype(jl_symbol("TypeMapEntry"), jl_any_type, jl_emptysvec, - jl_svec(9, jl_symbol("next"), + jl_svec(10, jl_symbol("next"), jl_symbol("sig"), jl_symbol("tvars"), jl_symbol("simplesig"), @@ -3706,8 +3716,9 @@ void jl_init_types(void) jl_symbol("func"), jl_symbol("isleafsig"), jl_symbol("issimplesig"), - jl_symbol("va")), - jl_svec(9, jl_any_type, // Union{TypeMapEntry, Void} + jl_symbol("va"), + jl_symbol("weak")), + jl_svec(10, jl_any_type, // Union{TypeMapEntry, Void} jl_type_type, // TupleType jl_any_type, // Union{SimpleVector{TypeVar}, TypeVar} jl_any_type, // TupleType @@ -3715,6 +3726,7 @@ void jl_init_types(void) jl_any_type, // Any jl_bool_type, jl_bool_type, + jl_bool_type, jl_bool_type), 0, 1, 5); diff --git a/src/julia.h b/src/julia.h index 61cfceada5f39..0ccb05815bc1a 100644 --- a/src/julia.h +++ b/src/julia.h @@ -300,7 +300,7 @@ typedef struct { jl_value_t *primary; jl_svec_t *cache; // sorted array jl_svec_t *linearcache; // unsorted array - intptr_t uid; + uint32_t uid; struct _jl_methtable_t *mt; } jl_typename_t; @@ -416,6 +416,7 @@ typedef struct _jl_typemap_entry_t { int8_t isleafsig; // isleaftype(sig) & !any(isType, sig) : unsorted and very fast int8_t issimplesig; // all(isleaftype | isAny | isType | isVararg, sig) : sorted and fast int8_t va; // isVararg(sig) + int8_t weak; // will never overwrite a signature } jl_typemap_entry_t; // one level in a TypeMap tree @@ -426,9 +427,12 @@ struct jl_ordereddict_t { }; typedef struct _jl_typemap_level_t { JL_DATA_TYPE - struct jl_ordereddict_t arg1; - struct jl_ordereddict_t targ; - jl_typemap_entry_t *linear; // union jl_typemap_t (but no more levels) + jl_typemap_entry_t *bottom; // union jl_typemap_t (but no more levels) for entries which have no type at offs + struct jl_ordereddict_t targ; // contains Type{LeafType} + struct jl_ordereddict_t arg1; // contains LeafType + struct jl_ordereddict_t tname; // contains non-abstract Type{TypeName} + struct jl_ordereddict_t name1; // contains non-abstract TypeName + jl_typemap_entry_t *linear; // union jl_typemap_t (but no more levels) - most entries usually end up here union jl_typemap_t any; // type at offs is Any jl_value_t *key; // [nullable] } jl_typemap_level_t; @@ -997,7 +1001,9 @@ STATIC_INLINE int jl_is_leaf_type_(jl_value_t *v) // type constructors JL_DLLEXPORT jl_typename_t *jl_new_typename(jl_sym_t *name); -JL_DLLEXPORT jl_tvar_t *jl_new_typevar(jl_sym_t *name,jl_value_t *lb,jl_value_t *ub); +JL_DLLEXPORT jl_tvar_t *jl_new_typevar(jl_sym_t *name, jl_value_t *lb, jl_value_t *ub); +JL_DLLEXPORT jl_tvar_t *jl_new_typevar_(jl_sym_t *name, jl_value_t *lb, + jl_value_t *ub, jl_value_t *b); JL_DLLEXPORT jl_value_t *jl_apply_type(jl_value_t *tc, jl_svec_t *params); JL_DLLEXPORT jl_tupletype_t *jl_apply_tuple_type(jl_svec_t *params); JL_DLLEXPORT jl_tupletype_t *jl_apply_tuple_type_v(jl_value_t **p, size_t np); diff --git a/src/typemap.c b/src/typemap.c index 466eb26d0556f..75ccc283367fb 100644 --- a/src/typemap.c +++ b/src/typemap.c @@ -25,6 +25,24 @@ static int jl_is_any(jl_value_t *t1) !((jl_tvar_t*)t1)->bound)); } +static jl_value_t* jl_type_extract_name(jl_value_t *t1) +{ + if (jl_is_typector(t1)) + t1 = (jl_value_t*)((jl_typector_t*)t1)->body; + if (jl_is_vararg_type(t1)) { + return jl_type_extract_name(jl_tparam0(t1)); + } + else if (jl_is_typevar(t1)) { + return jl_type_extract_name(((jl_tvar_t*)t1)->ub); + } + else if (jl_is_datatype(t1)) { + jl_datatype_t *dt = (jl_datatype_t*)t1; + if (!dt->abstract && !is_kind(t1) && dt->name != jl_tuple_typename) + return (jl_value_t*)dt->name; + } + return NULL; +} + // ----- Type Signature Subtype Testing ----- // static int sig_match_by_type_leaf(jl_value_t **types, jl_tupletype_t *sig, size_t n) @@ -238,9 +256,13 @@ static jl_array_t *jl_alloc_int_1d(size_t np, size_t len) static inline union jl_typemap_t mtcache_hash_lookup(const struct jl_ordereddict_t *a, jl_value_t *ty, int8_t tparam, int8_t offs) { - uintptr_t uid = ((jl_datatype_t*)ty)->uid; + uintptr_t uid; union jl_typemap_t ml; ml.unknown = jl_nothing; + if (tparam & 2) + uid = ((jl_typename_t*)ty)->uid; + else + uid = ((jl_datatype_t*)ty)->uid; if (!uid) return ml; size_t idx = jl_intref(a->indexes, uid & (a->indexes->nrows-1)); @@ -255,8 +277,10 @@ union jl_typemap_t mtcache_hash_lookup(const struct jl_ordereddict_t *a, jl_valu else { assert(jl_typeof(ml.unknown) == (jl_value_t*)jl_typemap_entry_type); t = jl_field_type(ml.leaf->sig, offs); - if (tparam) + if (tparam & 1) t = jl_tparam0(t); + if (tparam & 2) + t = jl_type_extract_name(t); } if (t != ty) ml.unknown = jl_nothing; @@ -291,12 +315,17 @@ static void mtcache_rehash(struct jl_ordereddict_t *pa, size_t newlen, jl_value_ t = ml.node->key; } else { - assert(jl_typeof(ml.unknown) == (jl_value_t*)jl_typemap_entry_type); t = jl_field_type(ml.leaf->sig, offs); - if (tparam) + if (tparam & 1) t = jl_tparam0(t); + if (tparam & 2) + t = jl_type_extract_name(t); } - uintptr_t uid = ((jl_datatype_t*)t)->uid; + uintptr_t uid; + if (tparam & 2) + uid = ((jl_typename_t*)t)->uid; + else + uid = ((jl_datatype_t*)t)->uid; size_t newi = uid & (newlen - 1); if (jl_intref(n, newi) == 0) { jl_intset(n, newi, i); @@ -330,6 +359,10 @@ 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.values != (void*)jl_nothing) jl_typemap_rehash_array(&ml.node->arg1, ml.unknown, 0, offs); + if (ml.node->tname.values != (void*)jl_nothing) + jl_typemap_rehash_array(&ml.node->tname, ml.unknown, 3, offs); + if (ml.node->name1.values != (void*)jl_nothing) + jl_typemap_rehash_array(&ml.node->name1, ml.unknown, 2, offs); jl_typemap_rehash(ml.node->any, offs+1); } } @@ -337,48 +370,57 @@ void jl_typemap_rehash(union jl_typemap_t ml, int8_t offs) { static union jl_typemap_t *mtcache_hash_bp(struct jl_ordereddict_t *pa, jl_value_t *ty, int8_t tparam, int8_t offs, jl_value_t *parent) { - if (jl_is_datatype(ty)) { - uintptr_t uid = ((jl_datatype_t*)ty)->uid; + uintptr_t uid; + if (tparam & 2) { + //if (ty == jl_datatype_type->name || ty == jl_typector_type->name) + // return NULL; // this is already handled in jl_type_extract_name + uid = ((jl_typename_t*)ty)->uid; + } + else { + if (!jl_is_datatype(ty)) + return NULL; + uid = ((jl_datatype_t*)ty)->uid; if (!uid || is_kind(ty) || jl_has_typevars(ty)) // be careful not to put non-leaf types or DataType/TypeConstructor in the cache here, // since they should have a lower priority and need to go into the sorted list return NULL; - if (pa->values == (void*)jl_nothing) { - pa->indexes = jl_alloc_int_1d(0, INIT_CACHE_SIZE); - jl_gc_wb(parent, pa->indexes); - pa->values = jl_alloc_vec_any(0); - jl_gc_wb(parent, pa->values); + } + if (pa->values == (void*)jl_nothing) { + pa->indexes = jl_alloc_int_1d(0, INIT_CACHE_SIZE); + jl_gc_wb(parent, pa->indexes); + pa->values = jl_alloc_vec_any(0); + jl_gc_wb(parent, pa->values); + } + while (1) { + size_t slot = uid & (pa->indexes->nrows - 1); + size_t idx = jl_intref(pa->indexes, slot); + if (idx == 0) { + jl_array_ptr_1d_push(pa->values, jl_nothing); + idx = jl_array_len(pa->values); + if (idx > jl_max_int(pa->indexes)) + mtcache_rehash(pa, jl_array_len(pa->indexes), parent, tparam, offs); + jl_intset(pa->indexes, slot, idx); + return &((union jl_typemap_t*)jl_array_data(pa->values))[idx - 1]; } - while (1) { - size_t slot = uid & (pa->indexes->nrows - 1); - size_t idx = jl_intref(pa->indexes, slot); - if (idx == 0) { - jl_array_ptr_1d_push(pa->values, jl_nothing); - idx = jl_array_len(pa->values); - if (idx > jl_max_int(pa->indexes)) - mtcache_rehash(pa, jl_array_len(pa->indexes), parent, tparam, offs); - jl_intset(pa->indexes, slot, idx); - return &((union jl_typemap_t*)jl_array_data(pa->values))[idx - 1]; - } - union jl_typemap_t *pml = &((union jl_typemap_t*)jl_array_data(pa->values))[idx - 1]; - if (pml->unknown == jl_nothing) - return pml; - jl_value_t *t; - if (jl_typeof(pml->unknown) == (jl_value_t*)jl_typemap_level_type) { - t = pml->node->key; - } - else { - assert(jl_typeof(pml->unknown) == (jl_value_t*)jl_typemap_entry_type); - t = jl_field_type(pml->leaf->sig, offs); - if (tparam) - t = jl_tparam0(t); - } - if (t == ty) - return pml; - mtcache_rehash(pa, jl_array_len(pa->indexes) * 2, parent, tparam, offs); + union jl_typemap_t *pml = &((union jl_typemap_t*)jl_array_data(pa->values))[idx - 1]; + if (pml->unknown == jl_nothing) + return pml; + jl_value_t *t; + if (jl_typeof(pml->unknown) == (jl_value_t*)jl_typemap_level_type) { + t = pml->node->key; } + else { + assert(jl_typeof(pml->unknown) == (jl_value_t*)jl_typemap_entry_type); + t = jl_field_type(pml->leaf->sig, offs); + if (tparam & 1) + t = jl_tparam0(t); + if (tparam & 2) + t = jl_type_extract_name(t); + } + if (t == ty) + return pml; + mtcache_rehash(pa, jl_array_len(pa->indexes) * 2, parent, tparam, offs); } - return NULL; } @@ -439,12 +481,21 @@ static int jl_typemap_node_visitor(jl_typemap_entry_t *ml, jl_typemap_visitor_fp int jl_typemap_visitor(union jl_typemap_t cache, jl_typemap_visitor_fptr fptr, void *closure) { if (jl_typeof(cache.unknown) == (jl_value_t*)jl_typemap_level_type) { + if (cache.node->bottom != (void*)jl_nothing) + if (!jl_typemap_node_visitor(cache.node->bottom, fptr, closure)) + return 0; if (cache.node->targ.values != (void*)jl_nothing) if (!jl_typemap_array_visitor(&cache.node->targ, fptr, closure)) return 0; if (cache.node->arg1.values != (void*)jl_nothing) if (!jl_typemap_array_visitor(&cache.node->arg1, fptr, closure)) return 0; + if (cache.node->tname.values != (void*)jl_nothing) + if (!jl_typemap_array_visitor(&cache.node->tname, fptr, closure)) + return 0; + if (cache.node->name1.values != (void*)jl_nothing) + if (!jl_typemap_array_visitor(&cache.node->name1, 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); @@ -476,19 +527,25 @@ static int jl_typemap_intersection_array_visitor(struct jl_ordereddict_t *a, jl_ } else { t = jl_field_type(ml.leaf->sig, offs); - if (tparam) + if (tparam & 1) t = jl_tparam0(t); } - if (ty == (jl_value_t*)jl_any_type || // easy case: Any always matches - (tparam ? // need to compute `ty <: Type{t}` - (jl_is_uniontype(ty) || // punt on Union{...} right now - jl_typeof(t) == ty || // deal with kinds (e.g. ty == DataType && t == Type{t}) - (jl_is_type_type(ty) && (jl_is_typevar(jl_tparam0(ty)) ? - jl_subtype(t, ((jl_tvar_t*)jl_tparam0(ty))->ub, 0) : // deal with ty == Type{<:T} - jl_subtype(t, jl_tparam0(ty), 0)))) // deal with ty == Type{T{#<:T}} - : jl_subtype(t, ty, 0))) // `t` is a leaftype, so intersection test becomes subtype + if (tparam & 2) { + // TODO: fast path rejection test if (!jl_typemap_intersection_visitor(ml, offs+1, closure)) return 0; + } else { + if (ty == (jl_value_t*)jl_any_type || // easy case: Any always matches + (tparam ? // need to compute `ty <: Type{t}` + (jl_is_uniontype(ty) || // punt on Union{...} right now + jl_typeof(t) == ty || // deal with kinds (e.g. ty == DataType && t == Type{t}) + (jl_is_type_type(ty) && (jl_is_typevar(jl_tparam0(ty)) ? + jl_subtype(t, ((jl_tvar_t*)jl_tparam0(ty))->ub, 0) : // deal with ty == Type{<:T} + jl_subtype(t, jl_tparam0(ty), 0)))) // deal with ty == Type{T{#<:T}} + : jl_subtype(t, ty, 0))) // `t` is a leaftype, so intersection test becomes subtype + if (!jl_typemap_intersection_visitor(ml, offs+1, closure)) + return 0; + } } return 1; } @@ -539,48 +596,58 @@ int jl_typemap_intersection_visitor(union jl_typemap_t map, int offs, size_t l = jl_field_count(closure->type); if (closure->va && l <= offs + 1) { ty = closure->va; + if (!jl_typemap_intersection_node_visitor(map.node->bottom, closure)) + return 0; } else if (l > offs) { ty = jl_tparam(closure->type, offs); } - if (ty) { - if (cache->targ.values != (void*)jl_nothing) { - jl_value_t *typetype = jl_is_type_type(ty) ? jl_tparam0(ty) : NULL; - if (typetype && !jl_has_typevars(typetype)) { - if (is_cache_leaf(typetype)) { - // direct lookup of leaf types - union jl_typemap_t ml = mtcache_hash_lookup(&cache->targ, typetype, 1, offs); - if (ml.unknown != jl_nothing) { - if (!jl_typemap_intersection_visitor(ml, offs+1, closure)) return 0; - } - } - } - else { - // else an array scan is required to check subtypes - // first, fast-path: optimized pre-intersection test to see if `ty` could intersect with any Type - if (typetype || jl_type_intersection((jl_value_t*)jl_type_type, ty) != jl_bottom_type) - if (!jl_typemap_intersection_array_visitor(&cache->targ, ty, 1, offs, closure)) return 0; - } - } - if (cache->arg1.values != (void*)jl_nothing) { - if (is_cache_leaf(ty)) { + else { + return jl_typemap_intersection_node_visitor(map.node->bottom, closure); + } + if (cache->targ.values != (void*)jl_nothing) { + jl_value_t *typetype = jl_is_type_type(ty) ? jl_tparam0(ty) : NULL; + if (typetype && !jl_has_typevars(typetype)) { + if (is_cache_leaf(typetype)) { // direct lookup of leaf types - union jl_typemap_t ml = mtcache_hash_lookup(&cache->arg1, ty, 0, offs); + union jl_typemap_t ml = mtcache_hash_lookup(&cache->targ, typetype, 1, offs); if (ml.unknown != jl_nothing) { if (!jl_typemap_intersection_visitor(ml, offs+1, closure)) return 0; } } - else { - // else an array scan is required to check subtypes - if (!jl_typemap_intersection_array_visitor(&cache->arg1, ty, 0, offs, closure)) return 0; + } + else { + // else an array scan is required to check subtypes + // first, fast-path: optimized pre-intersection test to see if `ty` could intersect with any Type + if (typetype || jl_type_intersection((jl_value_t*)jl_type_type, ty) != jl_bottom_type) + if (!jl_typemap_intersection_array_visitor(&cache->targ, ty, 1, offs, closure)) return 0; + } + } + if (cache->arg1.values != (void*)jl_nothing) { + if (is_cache_leaf(ty)) { + // direct lookup of leaf types + union jl_typemap_t ml = mtcache_hash_lookup(&cache->arg1, ty, 0, offs); + if (ml.unknown != jl_nothing) { + if (!jl_typemap_intersection_visitor(ml, offs+1, closure)) return 0; } } + else { + // else an array scan is required to check subtypes + if (!jl_typemap_intersection_array_visitor(&cache->arg1, ty, 0, offs, closure)) return 0; + } + } + if (cache->tname.values != (void*)jl_nothing) { + // TODO: optimized fast path + //jl_value_t *typetype = jl_is_type_type(ty) ? jl_tparam0(ty) : NULL; + if (!jl_typemap_intersection_array_visitor(&cache->tname, ty, 3, offs, closure)) return 0; + } + if (cache->name1.values != (void*)jl_nothing) { + // TODO: optimized fast path + if (!jl_typemap_intersection_array_visitor(&cache->name1, ty, 2, offs, closure)) return 0; } if (!jl_typemap_intersection_node_visitor(map.node->linear, closure)) return 0; - if (ty) - return jl_typemap_intersection_visitor(map.node->any, offs+1, closure); - return 1; + return jl_typemap_intersection_visitor(map.node->any, offs+1, closure); } else { return jl_typemap_intersection_node_visitor(map.leaf, closure); @@ -727,22 +794,34 @@ jl_typemap_entry_t *jl_typemap_assoc_by_type(union jl_typemap_t ml_or_cache, jl_ if (jl_is_vararg_type(ty)) { ty = jl_tparam0(ty); isva = 1; + jl_typemap_entry_t *li = subtype ? + jl_typemap_assoc_by_type_(cache->bottom, types, subtype_inexact__sigseq_useenv, penv) : + jl_typemap_lookup_by_type_(cache->bottom, types, subtype_inexact__sigseq_useenv); + if (li) return li; } else if (l <= offs) { - ty = NULL; + return subtype ? + jl_typemap_assoc_by_type_(cache->bottom, types, subtype_inexact__sigseq_useenv, penv) : + jl_typemap_lookup_by_type_(cache->bottom, types, subtype_inexact__sigseq_useenv); } } else if (l > offs) { ty = jl_tparam(types, offs); } - // If there is a type at offs, look in the optimized caches + else { + return subtype ? + jl_typemap_assoc_by_type_(cache->bottom, types, subtype_inexact__sigseq_useenv, penv) : + jl_typemap_lookup_by_type_(cache->bottom, types, subtype_inexact__sigseq_useenv); + } + // If there is a type at offs, look in the optimized leaf type caches if (!subtype) { - if (ty && jl_is_any(ty)) + if (jl_is_any(ty)) return jl_typemap_assoc_by_type(cache->any, types, penv, subtype_inexact__sigseq_useenv, subtype, offs+1); if (isva) // in lookup mode, want to match Vararg exactly, not as a subtype ty = NULL; } if (ty) { + // now look at the optimized leaftype caches if (jl_is_type_type(ty)) { jl_value_t *a0 = jl_tparam0(ty); if (cache->targ.values != (void*)jl_nothing && jl_is_datatype(a0)) { @@ -764,6 +843,29 @@ jl_typemap_entry_t *jl_typemap_assoc_by_type(union jl_typemap_t ml_or_cache, jl_ } } if (!subtype && is_cache_leaf(ty)) return NULL; + // now look at the optimized TypeName caches + if (cache->tname.values != (void*)jl_nothing && jl_is_type_type(ty)) { + jl_value_t *a0 = jl_type_extract_name(jl_tparam0(ty)); + if (a0) { + union jl_typemap_t ml = mtcache_hash_lookup(&cache->tname, a0, 3, offs); + 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 (cache->name1.values != (void*)jl_nothing) { + jl_value_t *a0 = jl_type_extract_name(ty); + if (a0) { + union jl_typemap_t ml = mtcache_hash_lookup(&cache->name1, a0, 2, offs); + 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; + } + } + } } // Always check the list (since offs doesn't always start at 0) if (subtype) { @@ -858,7 +960,9 @@ jl_typemap_entry_t *jl_typemap_entry_assoc_exact(jl_typemap_entry_t *ml, jl_valu jl_typemap_entry_t *jl_typemap_level_assoc_exact(jl_typemap_level_t *cache, jl_value_t **args, size_t n, int8_t offs) { - if (n > offs) { + if (n <= offs) { + return jl_typemap_entry_assoc_exact(cache->bottom, args, n); + } else { jl_value_t *a1 = args[offs]; jl_value_t *ty = (jl_value_t*)jl_typeof(a1); assert(jl_is_datatype(ty)); @@ -872,6 +976,16 @@ jl_typemap_entry_t *jl_typemap_level_assoc_exact(jl_typemap_level_t *cache, jl_v jl_typemap_entry_t *ml = jl_typemap_assoc_exact(ml_or_cache, args, n, offs+1); if (ml) return ml; } + if (ty == (jl_value_t*)jl_datatype_type && cache->tname.values != (void*)jl_nothing) { + union jl_typemap_t ml_or_cache = mtcache_hash_lookup(&cache->tname, (jl_value_t*)((jl_datatype_t*)a1)->name, 3, offs); + jl_typemap_entry_t *ml = jl_typemap_assoc_exact(ml_or_cache, args, n, offs+1); + if (ml) return ml; + } + if (cache->name1.values != (void*)jl_nothing) { + union jl_typemap_t ml_or_cache = mtcache_hash_lookup(&cache->name1, (jl_value_t*)((jl_datatype_t*)ty)->name, 2, offs); + jl_typemap_entry_t *ml = jl_typemap_assoc_exact(ml_or_cache, args, n, offs+1); + if (ml) return ml; + } } if (cache->linear != (jl_typemap_entry_t*)jl_nothing) { jl_typemap_entry_t *ml = jl_typemap_entry_assoc_exact(cache->linear, args, n); @@ -895,7 +1009,8 @@ static unsigned jl_typemap_list_count(jl_typemap_entry_t *ml) return count; } -static void jl_typemap_level_insert_(jl_typemap_level_t *cache, jl_typemap_entry_t *newrec, int8_t offs, const struct jl_typemap_info *tparams); +static void jl_typemap_level_insert_(jl_typemap_level_t *cache, jl_typemap_entry_t *newrec, int8_t offs, + const struct jl_typemap_info *tparams); static void jl_typemap_list_insert_sorted(jl_typemap_entry_t **pml, jl_value_t *parent, jl_typemap_entry_t *newrec, const struct jl_typemap_info *tparams); @@ -906,16 +1021,22 @@ static jl_typemap_level_t *jl_new_typemap_level(void) (jl_typemap_level_t*)jl_gc_alloc(ptls, sizeof(jl_typemap_level_t), jl_typemap_level_type); cache->key = NULL; + cache->bottom = (jl_typemap_entry_t*)jl_nothing; cache->linear = (jl_typemap_entry_t*)jl_nothing; cache->any.unknown = jl_nothing; cache->targ.indexes = (jl_array_t*)jl_nothing; cache->targ.values = (jl_array_t*)jl_nothing; cache->arg1.indexes = (jl_array_t*)jl_nothing; cache->arg1.values = (jl_array_t*)jl_nothing; + cache->tname.indexes = (jl_array_t*)jl_nothing; + cache->tname.values = (jl_array_t*)jl_nothing; + cache->name1.indexes = (jl_array_t*)jl_nothing; + cache->name1.values = (jl_array_t*)jl_nothing; return cache; } -static jl_typemap_level_t *jl_method_convert_list_to_cache(jl_typemap_entry_t *ml, jl_value_t *key, int8_t offs) +static jl_typemap_level_t *jl_method_convert_list_to_cache(jl_typemap_entry_t *ml, jl_value_t *key, int8_t offs, + const struct jl_typemap_info *tparams) { jl_typemap_level_t *cache = jl_new_typemap_level(); cache->key = key; @@ -924,7 +1045,7 @@ static jl_typemap_level_t *jl_method_convert_list_to_cache(jl_typemap_entry_t *m while (ml != (void*)jl_nothing) { next = ml->next; ml->next = (jl_typemap_entry_t*)jl_nothing; - jl_typemap_level_insert_(cache, ml, offs, 0); + jl_typemap_level_insert_(cache, ml, offs, tparams); ml = next; } JL_GC_POP(); @@ -956,7 +1077,7 @@ static void jl_typemap_insert_generic(union jl_typemap_t *pml, jl_value_t *paren unsigned count = jl_typemap_list_count(pml->leaf); if (count > MAX_METHLIST_COUNT) { - pml->node = jl_method_convert_list_to_cache(pml->leaf, key, offs); + pml->node = jl_method_convert_list_to_cache(pml->leaf, key, offs, tparams); jl_gc_wb(parent, pml->node); jl_typemap_level_insert_(pml->node, newrec, offs, tparams); return; @@ -975,6 +1096,118 @@ static int jl_typemap_array_insert_(struct jl_ordereddict_t *cache, jl_value_t * return pml != NULL; } +static void jl_split_morespecific_typename(jl_typemap_entry_t *newrec, int8_t offs, + jl_typemap_level_t *cache, const struct jl_typemap_info *tparams) +{ + size_t siglen = jl_svec_len(newrec->sig->parameters); + if (siglen <= offs) // bound Vararg to the length of the signature + offs = siglen - 1; + jl_value_t *t1 = jl_tparam(newrec->sig, offs); + jl_tvar_t *tvar = NULL; + jl_value_t *vararg = NULL; + int vararg_pos = 0; + if (jl_is_typector(t1)) { + t1 = (jl_value_t*)((jl_typector_t*)t1)->body; + } + if (jl_is_vararg_type(t1)) { + vararg = t1; + vararg_pos = 1; + t1 = jl_tparam0(t1); + } + if (jl_is_typevar(t1)) { + tvar = (jl_tvar_t*)t1; + t1 = tvar->ub; + } + if (jl_is_vararg_type(t1)) { + assert(vararg == NULL); + vararg = t1; + vararg_pos = 2; + t1 = jl_tparam0(t1); + } + + if (jl_is_uniontype(t1)) { + jl_ptls_t ptls = jl_get_ptls_states(); + jl_value_t *splitsig = NULL; + jl_value_t *splitenv = NULL; + jl_value_t *temp = NULL; + JL_GC_PUSH3(&splitsig, &splitenv, &temp); + jl_uniontype_t *ut = (jl_uniontype_t*)t1; + size_t i, l = jl_svec_len(ut->types); + for (i = 0; i < l; i++) { + jl_value_t *elem = jl_svecref(ut->types, i); + jl_value_t *t0 = jl_is_type_type(elem) ? jl_type_extract_name(jl_tparam0(elem)) : NULL; + jl_value_t *a0 = jl_type_extract_name(elem); + if (t0 || a0) { + temp = elem; + if (vararg_pos == 2) + temp = (jl_value_t*)jl_wrap_vararg(temp, jl_tparam1(vararg)); + if (tvar != NULL && tvar->bound) { + temp = (jl_value_t*)jl_new_typevar_(tvar->name, tvar->lb, temp, jl_true); + jl_value_t *env[2]; + env[0] = (jl_value_t*)tvar; + env[1] = temp; + splitsig = jl_instantiate_type_with((jl_value_t*)newrec->sig, env, 1); + + if (jl_is_typevar(newrec->tvars)) { + splitenv = temp; + } + else { + size_t tv; + splitenv = (jl_value_t*)jl_alloc_svec_uninit(jl_svec_len(newrec->tvars)); + for (tv = 0; tv < jl_svec_len(newrec->tvars); tv++) { + jl_value_t *t = jl_svecref(newrec->tvars, tv); + jl_svecset(splitenv, tv, t == (jl_value_t*)tvar ? temp : t); + } + } + } + else { + if (tvar != NULL) + temp = (jl_value_t*)jl_new_typevar(tvar->name, tvar->lb, temp); + if (vararg_pos == 1) + temp = (jl_value_t*)jl_wrap_vararg(temp, jl_tparam1(vararg)); + splitsig = (jl_value_t*)jl_svec_copy(newrec->sig->parameters); + jl_svecset(splitsig, offs, temp); + splitsig = (jl_value_t*)jl_apply_tuple_type((jl_svec_t*)splitsig); + splitenv = (jl_value_t*)newrec->tvars; + } + + jl_typemap_entry_t *newrec2 = + (jl_typemap_entry_t*)jl_gc_alloc(ptls, sizeof(jl_typemap_entry_t), + jl_typemap_entry_type); + jl_set_typeof(newrec2, jl_typemap_entry_type); + *newrec2 = *newrec; // copy newrec to newrec2 + newrec2->sig = (jl_datatype_t*)splitsig; + newrec2->tvars = (jl_svec_t*)splitenv; + // TODO: ignore weak entries for some operations + newrec2->weak = 1; + temp = (jl_value_t*)newrec2; // gc-root + + int inserted = 0; + if (t0) { + union jl_typemap_t *pml = mtcache_hash_bp(&cache->tname, t0, 3, offs, (jl_value_t*)cache); + if (pml) { + jl_typemap_entry_t *ml = jl_typemap_assoc_by_type(*pml, newrec2->sig, NULL, 1, 0, offs+1); + if (ml == NULL) // don't overwrite an existing entry + jl_typemap_insert_generic(pml, (jl_value_t*)cache->tname.values, newrec2, t0, offs+1, tparams); + inserted = 1; + } + } + if (!inserted && a0) { + union jl_typemap_t *pml = mtcache_hash_bp(&cache->name1, a0, 2, offs, (jl_value_t*)cache); + if (pml) { + jl_typemap_entry_t *ml = jl_typemap_assoc_by_type(*pml, newrec2->sig, NULL, 1, 0, offs+1); + if (ml == NULL) // don't overwrite an existing entry + jl_typemap_insert_generic(pml, (jl_value_t*)cache->name1.values, newrec2, a0, offs+1, tparams); + inserted = 1; + } + } + } + } + JL_GC_POP(); + } +} + + static void jl_typemap_level_insert_(jl_typemap_level_t *cache, jl_typemap_entry_t *newrec, int8_t offs, const struct jl_typemap_info *tparams) { @@ -995,22 +1228,43 @@ static void jl_typemap_level_insert_(jl_typemap_level_t *cache, jl_typemap_entry else if (l > offs) { t1 = jl_tparam(newrec->sig, offs); } + if (t1 == NULL) { + jl_typemap_list_insert_(&cache->bottom, (jl_value_t*)cache, newrec, tparams); + return; + } // If the type at `offs` is Any, put it in the Any list - if (t1 && jl_is_any(t1)) + 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); // Don't put Varargs in the optimized caches (too hard to handle in lookup and bp) - if (t1 && !isva) { - // if t1 != jl_typetype_type and the argument is Type{...}, this - // method has specializations for singleton kinds and we use - // the table indexed for that purpose. + if (!isva) { + // try to put in leaf type caches if (t1 != (jl_value_t*)jl_typetype_type && jl_is_type_type(t1)) { + // if t1 != jl_typetype_type and the argument is Type{...}, this + // method has specializations for singleton kinds and we use + // the table indexed for that purpose. jl_value_t *a0 = jl_tparam0(t1); if (jl_typemap_array_insert_(&cache->targ, a0, newrec, (jl_value_t*)cache, 1, offs, tparams)) return; } if (jl_typemap_array_insert_(&cache->arg1, t1, newrec, (jl_value_t*)cache, 0, offs, tparams)) return; + + // try to put in TypeName caches + jl_value_t *a0; + if (jl_is_type_type(t1)) { + a0 = jl_type_extract_name(jl_tparam0(t1)); + if (a0 && jl_typemap_array_insert_(&cache->tname, a0, newrec, (jl_value_t*)cache, 3, offs, tparams)) + return; + } + a0 = jl_type_extract_name(t1); + if (a0 && jl_typemap_array_insert_(&cache->name1, a0, newrec, (jl_value_t*)cache, 2, offs, tparams)) + return; } + // need to split this union into components that go into TypeName, and those less-specific + jl_split_morespecific_typename(newrec, offs, cache, tparams); + // always fall-through. newrec is unmodified since lessspec_sig <: newrec->sig, + // and the user might try to look up the original sig directly + // (either through invoke or exact extraction) jl_typemap_list_insert_(&cache->linear, (jl_value_t*)cache, newrec, tparams); } @@ -1039,6 +1293,7 @@ jl_typemap_entry_t *jl_typemap_insert(union jl_typemap_t *cache, jl_value_t *par jl_gc_wb(ml, ml->sig); ml->simplesig = simpletype; jl_gc_wb(ml, ml->simplesig); + assert((ml->tvars == jl_emptysvec) == (tvars == jl_emptysvec)); ml->tvars = tvars; jl_gc_wb(ml, ml->tvars); ml->va = jl_is_va_tuple(type); @@ -1056,6 +1311,7 @@ jl_typemap_entry_t *jl_typemap_insert(union jl_typemap_t *cache, jl_value_t *par jl_typemap_entry_t *newrec = (jl_typemap_entry_t*)jl_gc_alloc(ptls, sizeof(jl_typemap_entry_t), jl_typemap_entry_type); + newrec->weak = 0; newrec->sig = type; newrec->simplesig = simpletype; newrec->tvars = tvars;