Skip to content

Commit 80aeebe

Browse files
authored
Don't perform extra inference during incremental image creation (#48054)
As noted in #48047, we're currently attempting to infer extra methods during incremental image saving, which causes us to miss edges in the image. In particular, in the case of #48047, Cthulhu had the `compile=min` option set, which caused the code instance for `do_typeinf!` to not be infered. However, later it was nevertheless queued for precompilation, causing inference to occur at an inopportune time. This PR simply prevents code instances that don't explicitly have the `->precompile` flag set (e.g. the guard instance created for the interpreter) from being enqueued for precompilation. It is not clear that this is necessarily the correct behavior - we may in fact want to infer these method instances, just before we set up the serializer state, but for now this fixes #48047 for me. I also included an appropriate test and a warning message if we attempt to enter inference when this is not legal, so any revisit of what should be happening here can hopefully make use of those.
1 parent a9506f5 commit 80aeebe

File tree

4 files changed

+37
-2
lines changed

4 files changed

+37
-2
lines changed

base/Base.jl

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -447,6 +447,10 @@ for m in methods(include)
447447
delete_method(m)
448448
end
449449

450+
# This method is here only to be overwritten during the test suite to test
451+
# various sysimg related invalidation scenarios.
452+
a_method_to_overwrite_in_test() = inferencebarrier(1)
453+
450454
# These functions are duplicated in client.jl/include(::String) for
451455
# nicer stacktraces. Modifications here have to be backported there
452456
include(mod::Module, _path::AbstractString) = _include(identity, mod, _path)

src/gf.c

Lines changed: 7 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -280,6 +280,13 @@ jl_code_info_t *jl_type_infer(jl_method_instance_t *mi, size_t world, int force)
280280
if (jl_typeinf_func == NULL)
281281
return NULL;
282282
jl_task_t *ct = jl_current_task;
283+
if (ct->reentrant_inference == (uint16_t)-1) {
284+
// TODO: We should avoid attempting to re-inter inference here at all
285+
// and turn on this warning, but that requires further refactoring
286+
// of the precompile code, so for now just catch that case here.
287+
//jl_printf(JL_STDERR, "ERROR: Attempted to enter inference while writing out image.");
288+
return NULL;
289+
}
283290
if (ct->reentrant_inference > 2)
284291
return NULL;
285292

src/staticdata.c

Lines changed: 9 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -2614,7 +2614,12 @@ JL_DLLEXPORT void jl_create_system_image(void **_native_data, jl_array_t *workli
26142614
} else {
26152615
checksumpos_ff = checksumpos;
26162616
}
2617-
jl_gc_enable_finalizers(ct, 0); // make sure we don't run any Julia code concurrently after this point
2617+
{
2618+
// make sure we don't run any Julia code concurrently after this point
2619+
jl_gc_enable_finalizers(ct, 0);
2620+
assert(ct->reentrant_inference == 0);
2621+
ct->reentrant_inference = (uint16_t)-1;
2622+
}
26182623
jl_prepare_serialization_data(mod_array, newly_inferred, jl_worklist_key(worklist), &extext_methods, &new_specializations, &method_roots_list, &ext_targets, &edges);
26192624

26202625
// Generate _native_data`
@@ -2638,7 +2643,9 @@ JL_DLLEXPORT void jl_create_system_image(void **_native_data, jl_array_t *workli
26382643
jl_save_system_image_to_stream(ff, worklist, extext_methods, new_specializations, method_roots_list, ext_targets, edges);
26392644
native_functions = NULL;
26402645
if (worklist) {
2641-
jl_gc_enable_finalizers(ct, 1); // make sure we don't run any Julia code concurrently before this point
2646+
// Re-enable running julia code for postoutput hooks, atexit, etc.
2647+
jl_gc_enable_finalizers(ct, 1);
2648+
ct->reentrant_inference = 0;
26422649
jl_precompile_toplevel_module = NULL;
26432650
}
26442651

test/precompile.jl

Lines changed: 17 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1691,6 +1691,23 @@ precompile_test_harness("DynamicExpressions") do load_path
16911691
end
16921692
end
16931693

1694+
precompile_test_harness("BadInvalidations") do load_path
1695+
write(joinpath(load_path, "BadInvalidations.jl"),
1696+
"""
1697+
module BadInvalidations
1698+
Base.Experimental.@compiler_options compile=min optimize=1
1699+
getval() = Base.a_method_to_overwrite_in_test()
1700+
getval()
1701+
end # module BadInvalidations
1702+
""")
1703+
Base.compilecache(Base.PkgId("BadInvalidations"))
1704+
(@eval Base a_method_to_overwrite_in_test() = inferencebarrier(2))
1705+
(@eval (using BadInvalidations))
1706+
Base.invokelatest() do
1707+
@test BadInvalidations.getval() === 2
1708+
end
1709+
end
1710+
16941711
empty!(Base.DEPOT_PATH)
16951712
append!(Base.DEPOT_PATH, original_depot_path)
16961713
empty!(Base.LOAD_PATH)

0 commit comments

Comments
 (0)