Skip to content

Commit

Permalink
Check world age bounds on candidate ambiguities. Fixes #28899
Browse files Browse the repository at this point in the history
  • Loading branch information
timholy committed Aug 29, 2018
1 parent 39e5742 commit aae182b
Show file tree
Hide file tree
Showing 10 changed files with 30 additions and 15 deletions.
7 changes: 6 additions & 1 deletion base/compiler/utilities.jl
Original file line number Diff line number Diff line change
Expand Up @@ -112,6 +112,11 @@ function retrieve_code_info(linfo::MethodInstance)
return get_staged(linfo)
else
# TODO: post-inference see if we can swap back to the original arrays?
println(linfo)
println(linfo.def)
println(typeof(linfo.def))
println(typeof(m.source))
println(m.source)
if isa(m.source, Array{UInt8,1})
c = ccall(:jl_uncompress_ast, Any, (Any, Any), m, m.source)
else
Expand All @@ -122,7 +127,7 @@ function retrieve_code_info(linfo::MethodInstance)
end

function code_for_method(method::Method, @nospecialize(atypes), sparams::SimpleVector, world::UInt, preexisting::Bool=false)
if world < min_world(method)
if world < min_world(method) || world > max_world(method)
return nothing
end
if isdefined(method, :generator) && !isdispatchtuple(atypes)
Expand Down
2 changes: 2 additions & 0 deletions base/errorshow.jl
Original file line number Diff line number Diff line change
Expand Up @@ -432,6 +432,8 @@ function show_method_candidates(io::IO, ex::MethodError, @nospecialize kwargs=()
end
if ex.world < min_world(method)
print(iob, " (method too new to be called from this world context.)")
elseif ex.world > max_world(method)
print(iob, " (method deleted before this world age.)")
end
# TODO: indicate if it's in the wrong world
push!(lines, (buf, right_matches))
Expand Down
2 changes: 1 addition & 1 deletion base/methodshow.jl
Original file line number Diff line number Diff line change
Expand Up @@ -76,7 +76,7 @@ end

function kwarg_decl(m::Method, kwtype::DataType)
sig = rewrap_unionall(Tuple{kwtype, Any, unwrap_unionall(m.sig).parameters...}, m.sig)
kwli = ccall(:jl_methtable_lookup, Any, (Any, Any, UInt), kwtype.name.mt, sig, typemax(UInt))
kwli = ccall(:jl_methtable_lookup, Any, (Any, Any, UInt), kwtype.name.mt, sig, max_world(m))
if kwli !== nothing
kwli = kwli::Method
src = uncompressed_ast(kwli)
Expand Down
2 changes: 1 addition & 1 deletion base/reflection.jl
Original file line number Diff line number Diff line change
Expand Up @@ -1101,7 +1101,7 @@ has_bottom_parameter(t::TypeVar) = t.ub == Bottom || has_bottom_parameter(t.ub)
has_bottom_parameter(::Any) = false

min_world(m::Method) = reinterpret(UInt, m.min_world)
max_world(m::Method) = typemax(UInt)
max_world(m::Method) = reinterpret(UInt, m.max_world)
min_world(m::Core.MethodInstance) = reinterpret(UInt, m.min_world)
max_world(m::Core.MethodInstance) = reinterpret(UInt, m.max_world)

Expand Down
1 change: 1 addition & 0 deletions src/dump.c
Original file line number Diff line number Diff line change
Expand Up @@ -1644,6 +1644,7 @@ static jl_value_t *jl_deserialize_value_method(jl_serializer_state *s, jl_value_
m->file = (jl_sym_t*)jl_deserialize_value(s, NULL);
m->line = read_int32(s->s);
m->min_world = jl_world_counter;
m->max_world = ~(size_t)0;
m->ambig = jl_deserialize_value(s, (jl_value_t**)&m->ambig);
jl_gc_wb(m, m->ambig);
m->called = read_int32(s->s);
Expand Down
16 changes: 9 additions & 7 deletions src/gf.c
Original file line number Diff line number Diff line change
Expand Up @@ -148,7 +148,7 @@ static int8_t jl_cachearg_offset(jl_methtable_t *mt)
// get or create the MethodInstance for a specialization
JL_DLLEXPORT jl_method_instance_t *jl_specializations_get_linfo(jl_method_t *m JL_PROPAGATES_ROOT, jl_value_t *type, jl_svec_t *sparams, size_t world)
{
assert(world >= m->min_world && "typemap lookup is corrupted");
assert(world >= m->min_world && world <= m->max_world && "typemap lookup is corrupted");
JL_LOCK(&m->writelock);
jl_typemap_entry_t *sf =
jl_typemap_assoc_by_type(m->specializations, type, NULL, /*subtype*/0, /*offs*/0, world, /*max_world_mask*/0);
Expand All @@ -169,7 +169,7 @@ JL_DLLEXPORT jl_method_instance_t *jl_specializations_get_linfo(jl_method_t *m J
li->min_world = world;
}
if (world == jl_world_counter) {
li->max_world = ~(size_t)0;
li->max_world = m->max_world;
}
else {
li->max_world = world;
Expand Down Expand Up @@ -358,6 +358,7 @@ JL_DLLEXPORT jl_method_instance_t* jl_set_method_inferred(
else {
JL_LOCK(&li->def.method->writelock);
assert(min_world >= li->def.method->min_world);
assert(max_world <= li->def.method->max_world);
int isinferred = jl_is_rettype_inferred(li);
if (!isinferred && li->min_world >= min_world && li->max_world <= max_world) {
// expand the current (uninferred) entry to cover the full inferred range
Expand Down Expand Up @@ -955,7 +956,7 @@ static jl_method_instance_t *cache_method(
jl_tupletype_t *cachett = tt;
jl_svec_t* guardsigs = jl_emptysvec;
size_t min_valid = definition->min_world;
size_t max_valid = ~(size_t)0;
size_t max_valid = definition->max_world;
if (!cache_with_orig) {
// now examine what will happen if we chose to use this sig in the cache
temp = ml_matches(mt->defs, 0, compilationsig, -1, 0, world, &min_valid, &max_valid); // TODO: use MAX_UNSPECIALIZED_CONFLICTS?
Expand Down Expand Up @@ -1513,7 +1514,8 @@ JL_DLLEXPORT void jl_method_table_disable(jl_methtable_t *mt, jl_method_t *metho
jl_typemap_entry_t *methodentry = do_typemap_search(mt, method);
JL_LOCK(&mt->writelock);
// Narrow the world age on the method to make it uncallable
methodentry->max_world = jl_world_counter++;
method->max_world = jl_world_counter++;
methodentry->max_world = jl_world_counter;
// Recompute ambiguities (deleting a more specific method might reveal ambiguities that it previously resolved)
check_ambiguous_matches(mt->defs, methodentry, check_disabled_ambiguous_visitor); // TODO: decrease repeated work?
// Invalidate the backedges
Expand All @@ -1537,7 +1539,7 @@ JL_DLLEXPORT void jl_method_table_insert(jl_methtable_t *mt, jl_method_t *method
JL_LOCK(&mt->writelock);
jl_typemap_entry_t *newentry = jl_typemap_insert(&mt->defs, (jl_value_t*)mt,
(jl_tupletype_t*)type, simpletype, jl_emptysvec, (jl_value_t*)method, 0, &method_defs,
method->min_world, ~(size_t)0, &oldvalue);
method->min_world, method->max_world, &oldvalue);
if (oldvalue) {
if (oldvalue == (jl_value_t*)method) {
// redundant add of same method; no need to do anything
Expand Down Expand Up @@ -1995,7 +1997,7 @@ JL_DLLEXPORT int jl_is_call_ambiguous(jl_value_t *types, jl_method_t *m)
return 0;
for (size_t i = 0; i < jl_array_len(m->ambig); i++) {
jl_method_t *mambig = (jl_method_t*)jl_array_ptr_ref(m->ambig, i);
if (jl_subtype((jl_value_t*)types, (jl_value_t*)mambig->sig))
if (mambig->min_world <= jl_world_counter && jl_world_counter <= mambig->max_world && jl_subtype((jl_value_t*)types, (jl_value_t*)mambig->sig))
return 1;
}
return 0;
Expand All @@ -2009,7 +2011,7 @@ JL_DLLEXPORT int jl_has_call_ambiguities(jl_value_t *types, jl_method_t *m)
return 0;
for (size_t i = 0; i < jl_array_len(m->ambig); i++) {
jl_method_t *mambig = (jl_method_t*)jl_array_ptr_ref(m->ambig, i);
if (!jl_has_empty_intersection(mambig->sig, types))
if (mambig->min_world <= jl_world_counter && jl_world_counter <= mambig->max_world && !jl_has_empty_intersection(mambig->sig, types))
return 1;
}
return 0;
Expand Down
8 changes: 5 additions & 3 deletions src/jltypes.c
Original file line number Diff line number Diff line change
Expand Up @@ -2063,13 +2063,14 @@ void jl_init_types(void) JL_GC_DISABLED
jl_method_type =
jl_new_datatype(jl_symbol("Method"), core,
jl_any_type, jl_emptysvec,
jl_perm_symsvec(19,
jl_perm_symsvec(20,
"name",
"module",
"file",
"line",
"sig",
"min_world",
"max_world",
"ambig",
"specializations",
"sparam_syms",
Expand All @@ -2083,13 +2084,14 @@ void jl_init_types(void) JL_GC_DISABLED
"nospecialize",
"isva",
"pure"),
jl_svec(19,
jl_svec(20,
jl_sym_type,
jl_module_type,
jl_sym_type,
jl_int32_type,
jl_type_type,
jl_long_type,
jl_long_type,
jl_any_type, // Union{Array, Nothing}
jl_any_type, // TypeMap
jl_simplevector_type,
Expand All @@ -2103,7 +2105,7 @@ void jl_init_types(void) JL_GC_DISABLED
jl_int32_type,
jl_bool_type,
jl_bool_type),
0, 1, 9);
0, 1, 10);

jl_method_instance_type =
jl_new_datatype(jl_symbol("MethodInstance"), core,
Expand Down
1 change: 1 addition & 0 deletions src/julia.h
Original file line number Diff line number Diff line change
Expand Up @@ -266,6 +266,7 @@ typedef struct _jl_method_t {
// method's type signature. redundant with TypeMapEntry->specTypes
jl_value_t *sig;
size_t min_world;
size_t max_world;

// list of potentially-ambiguous methods (nothing = none, Vector{Any} of Methods otherwise)
jl_value_t *ambig;
Expand Down
4 changes: 3 additions & 1 deletion src/method.c
Original file line number Diff line number Diff line change
Expand Up @@ -460,7 +460,7 @@ jl_method_instance_t *jl_get_specialized(jl_method_t *m, jl_value_t *types, jl_s
new_linfo->specTypes = types;
new_linfo->sparam_vals = sp;
new_linfo->min_world = m->min_world;
new_linfo->max_world = ~(size_t)0;
new_linfo->max_world = m->max_world;
return new_linfo;
}

Expand Down Expand Up @@ -595,6 +595,7 @@ JL_DLLEXPORT jl_method_t *jl_new_method_uninit(jl_module_t *module)
m->nargs = 0;
m->traced = 0;
m->min_world = 1;
m->max_world = ~(size_t)0;
JL_MUTEX_INIT(&m->writelock);
return m;
}
Expand Down Expand Up @@ -639,6 +640,7 @@ static jl_method_t *jl_new_method(

JL_GC_POP();
m->min_world = ++jl_world_counter;
m->max_world = ~(size_t)0;
return m;
}

Expand Down
2 changes: 1 addition & 1 deletion src/typemap.c
Original file line number Diff line number Diff line change
Expand Up @@ -744,7 +744,7 @@ jl_typemap_entry_t *jl_typemap_entry_assoc_exact(jl_typemap_entry_t *ml, jl_valu
{
// some manually-unrolled common special cases
while (ml->simplesig == (void*)jl_nothing && ml->guardsigs == jl_emptysvec && ml->isleafsig) {
// use a tight loop for a long as possible
// use a tight loop for as long as possible
if (world >= ml->min_world && world <= ml->max_world) {
if (n == jl_field_count(ml->sig) && jl_typeof(args[0]) == jl_tparam(ml->sig, 0)) {
if (n == 1)
Expand Down

0 comments on commit aae182b

Please sign in to comment.