Skip to content

Commit

Permalink
add a typemap level specifically for Any
Browse files Browse the repository at this point in the history
  • Loading branch information
vtjnash committed May 7, 2016
1 parent 26cebb6 commit 56fd188
Show file tree
Hide file tree
Showing 5 changed files with 138 additions and 103 deletions.
1 change: 1 addition & 0 deletions base/reflection.jl
Original file line number Diff line number Diff line change
Expand Up @@ -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)
Expand Down
6 changes: 4 additions & 2 deletions src/dump.c
Original file line number Diff line number Diff line change
Expand Up @@ -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++) {
Expand All @@ -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;
}
Expand Down
6 changes: 3 additions & 3 deletions src/jltypes.c
Original file line number Diff line number Diff line change
Expand Up @@ -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,
Expand Down
1 change: 1 addition & 0 deletions src/julia.h
Original file line number Diff line number Diff line change
Expand Up @@ -408,6 +408,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;

Expand Down
227 changes: 129 additions & 98 deletions src/typemap.c
Original file line number Diff line number Diff line change
Expand Up @@ -16,6 +16,11 @@
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)
Expand Down Expand Up @@ -331,25 +336,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
Expand Down Expand Up @@ -386,10 +398,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;
Expand Down Expand Up @@ -429,43 +476,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)
Expand Down Expand Up @@ -585,21 +602,20 @@ 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)) {
union jl_typemap_t ml = mtcache_hash_lookup(cache->targ, a0, 1, 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 (li) return li;
}
}
}
Expand All @@ -608,25 +624,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) {
Expand All @@ -635,9 +694,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);
Expand Down Expand Up @@ -665,51 +723,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)
Expand All @@ -732,6 +760,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;
Expand Down Expand Up @@ -813,6 +842,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);
}
Expand Down

0 comments on commit 56fd188

Please sign in to comment.