Skip to content

Commit c1a0bb2

Browse files
committed
avoid invalidations when the overlap is ambiguous
In these cases, the new method would not be called because the call would be an ambiguity error instead.
1 parent db90631 commit c1a0bb2

File tree

1 file changed

+25
-6
lines changed

1 file changed

+25
-6
lines changed

src/gf.c

Lines changed: 25 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -1682,18 +1682,33 @@ JL_DLLEXPORT void jl_method_table_disable(jl_methtable_t *mt, jl_method_t *metho
16821682
JL_UNLOCK(&mt->writelock);
16831683
}
16841684

1685+
static int is_call_ambiguous(jl_methtable_t *mt, jl_value_t *types JL_PROPAGATES_ROOT, size_t world)
1686+
{
1687+
struct jl_typemap_assoc search = {(jl_value_t*)types, world, NULL, 0, ~(size_t)0};
1688+
jl_typemap_entry_t *entry = jl_typemap_assoc_by_type(mt->defs, &search, /*offs*/0, /*subtype*/1);
1689+
if (entry == NULL)
1690+
return 0; // we added a new definition to consider
1691+
jl_typemap_entry_t *m = jl_typemap_morespecific_by_type(entry, (jl_value_t*)types, NULL, world);
1692+
if (m == NULL) {
1693+
// TODO: this isn't quite right, since we just ask if the entry dominates
1694+
// over all subtypes of `types`, but wanted to ask the inverse question
1695+
return 1; // a new ambiguity doesn't change the result of method lookup
1696+
}
1697+
return 0; // existing and/or method already covered this intersection (TODO: which is it?)
1698+
}
1699+
16851700
JL_DLLEXPORT void jl_method_table_insert(jl_methtable_t *mt, jl_method_t *method, jl_tupletype_t *simpletype)
16861701
{
16871702
JL_TIMING(ADD_METHOD);
16881703
assert(jl_is_method(method));
16891704
assert(jl_is_mtable(mt));
16901705
jl_value_t *type = method->sig;
1691-
jl_value_t *oldvalue = NULL;
1706+
jl_value_t *oldvalue = NULL, *isect = NULL;
16921707
if (method->primary_world == 1)
16931708
method->primary_world = ++jl_world_counter;
16941709
size_t max_world = method->primary_world - 1;
16951710
int invalidated = 0;
1696-
JL_GC_PUSH1(&oldvalue);
1711+
JL_GC_PUSH2(&oldvalue, &isect);
16971712
JL_LOCK(&mt->writelock);
16981713
// first delete the existing entry (we'll disable it later)
16991714
struct jl_typemap_assoc search = {(jl_value_t*)type, method->primary_world, NULL, 0, ~(size_t)0};
@@ -1718,7 +1733,8 @@ JL_DLLEXPORT void jl_method_table_insert(jl_methtable_t *mt, jl_method_t *method
17181733
size_t ins = 0;
17191734
for (i = 1; i < na; i += 2) {
17201735
jl_value_t *backedgetyp = backedges[i - 1];
1721-
if (!jl_has_empty_intersection(backedgetyp, (jl_value_t*)type)) {
1736+
isect = jl_type_intersection(backedgetyp, (jl_value_t*)type);
1737+
if (isect != jl_bottom_type && !is_call_ambiguous(mt, isect, max_world)) {
17221738
jl_method_instance_t *backedge = (jl_method_instance_t*)backedges[i];
17231739
invalidate_method_instance(backedge, max_world, 0);
17241740
invalidated = 1;
@@ -1766,9 +1782,12 @@ JL_DLLEXPORT void jl_method_table_insert(jl_methtable_t *mt, jl_method_t *method
17661782
size_t i, l = jl_svec_len(specializations);
17671783
for (i = 0; i < l; i++) {
17681784
jl_method_instance_t *mi = (jl_method_instance_t*)jl_svecref(specializations, i);
1769-
if (mi != NULL && !jl_has_empty_intersection(type, (jl_value_t*)mi->specTypes))
1770-
if (invalidate_backedges(mi, max_world))
1771-
invalidated = 1;
1785+
if (mi != NULL) {
1786+
isect = jl_type_intersection(type, (jl_value_t*)mi->specTypes);
1787+
if (isect != jl_bottom_type && !is_call_ambiguous(mt, isect, max_world))
1788+
if (invalidate_backedges(mi, max_world))
1789+
invalidated = 1;
1790+
}
17721791
}
17731792
}
17741793
}

0 commit comments

Comments
 (0)