Skip to content

Commit

Permalink
Validate CodeInstances with no external edges (JuliaLang#41961)
Browse files Browse the repository at this point in the history
In JuliaLang#38983 and JuliaLang#41872, it was discovered that only CodeInstances with
external backedges get validated after deserialization.
This adds a "second chance" for each CodeInstance: it validates any that
have neither been validated nor invalidated by the end of deserialization.

Closes JuliaLang#41872
  • Loading branch information
timholy authored and LilithHafner committed Mar 8, 2022
1 parent 54b6a58 commit 406778c
Show file tree
Hide file tree
Showing 2 changed files with 53 additions and 1 deletion.
26 changes: 25 additions & 1 deletion src/dump.c
Original file line number Diff line number Diff line change
Expand Up @@ -46,6 +46,7 @@ static jl_value_t *deser_symbols[256];
static htable_t backref_table;
static int backref_table_numel;
static arraylist_t backref_list;
static htable_t new_code_instance_validate;

// list of (jl_value_t **loc, size_t pos) entries
// for anything that was flagged by the deserializer for later
Expand Down Expand Up @@ -1616,8 +1617,10 @@ static jl_value_t *jl_deserialize_value_code_instance(jl_serializer_state *s, jl
codeinst->precompile = 1;
codeinst->next = (jl_code_instance_t*)jl_deserialize_value(s, (jl_value_t**)&codeinst->next);
jl_gc_wb(codeinst, codeinst->next);
if (validate)
if (validate) {
codeinst->min_world = jl_world_counter;
ptrhash_put(&new_code_instance_validate, codeinst, (void*)(~(uintptr_t)HT_NOTFOUND)); // "HT_FOUND"
}
return (jl_value_t*)codeinst;
}

Expand Down Expand Up @@ -2055,10 +2058,16 @@ static void jl_insert_backedges(jl_array_t *list, jl_array_t *targets)
while (codeinst) {
if (codeinst->min_world > 0)
codeinst->max_world = ~(size_t)0;
ptrhash_put(&new_code_instance_validate, codeinst, HT_NOTFOUND); // mark it as handled
codeinst = jl_atomic_load_relaxed(&codeinst->next);
}
}
else {
jl_code_instance_t *codeinst = caller->cache;
while (codeinst) {
ptrhash_put(&new_code_instance_validate, codeinst, HT_NOTFOUND); // should be left invalid
codeinst = jl_atomic_load_relaxed(&codeinst->next);
}
if (_jl_debug_method_invalidation) {
jl_array_ptr_1d_push(_jl_debug_method_invalidation, (jl_value_t*)caller);
loctag = jl_cstr_to_string("insert_backedges");
Expand All @@ -2069,6 +2078,16 @@ static void jl_insert_backedges(jl_array_t *list, jl_array_t *targets)
JL_GC_POP();
}

static void validate_new_code_instances(void)
{
size_t i;
for (i = 0; i < new_code_instance_validate.size; i += 2) {
if (new_code_instance_validate.table[i+1] != HT_NOTFOUND) {
((jl_code_instance_t*)new_code_instance_validate.table[i])->max_world = ~(size_t)0;
new_code_instance_validate.table[i+1] = HT_NOTFOUND;
}
}
}

static jl_value_t *read_verify_mod_list(ios_t *s, jl_array_t *mod_list)
{
Expand Down Expand Up @@ -2636,6 +2655,7 @@ static jl_value_t *_jl_restore_incremental(ios_t *f, jl_array_t *mod_array)
arraylist_new(&backref_list, 4000);
arraylist_push(&backref_list, jl_main_module);
arraylist_new(&flagref_list, 0);
htable_new(&new_code_instance_validate, 0);
arraylist_new(&ccallable_list, 0);
htable_new(&uniquing_table, 0);

Expand Down Expand Up @@ -2671,7 +2691,11 @@ static jl_value_t *_jl_restore_incremental(ios_t *f, jl_array_t *mod_array)

jl_insert_backedges((jl_array_t*)external_backedges, (jl_array_t*)external_edges); // restore external backedges (needs to be last)

// check new CodeInstances and validate any that lack external backedges
validate_new_code_instances();

serializer_worklist = NULL;
htable_free(&new_code_instance_validate);
arraylist_free(&flagref_list);
arraylist_free(&backref_list);
ios_close(f);
Expand Down
28 changes: 28 additions & 0 deletions test/precompile.jl
Original file line number Diff line number Diff line change
Expand Up @@ -876,6 +876,34 @@ precompile_test_harness("Renamed Imports") do load_path
@test (@eval (using RenameImports; RenameImports.test())) isa Module
end

# issue #41872 (example from #38983)
precompile_test_harness("No external edges") do load_path
write(joinpath(load_path, "NoExternalEdges.jl"),
"""
module NoExternalEdges
bar(x::Int) = hcat(rand())
@inline bar() = hcat(rand())
bar(x::Float64) = bar()
foo1() = bar(1)
foo2() = bar(1.0)
foo3() = bar()
foo4() = hcat(rand())
precompile(foo1, ())
precompile(foo2, ())
precompile(foo3, ())
precompile(foo4, ())
end
""")
Base.compilecache(Base.PkgId("NoExternalEdges"))
@eval begin
using NoExternalEdges
@test only(methods(NoExternalEdges.foo1)).specializations[1].cache.max_world != 0
@test only(methods(NoExternalEdges.foo2)).specializations[1].cache.max_world != 0
@test only(methods(NoExternalEdges.foo3)).specializations[1].cache.max_world != 0
@test only(methods(NoExternalEdges.foo4)).specializations[1].cache.max_world != 0
end
end

@testset "issue 38149" begin
M = Module()
@eval M begin
Expand Down

0 comments on commit 406778c

Please sign in to comment.