Skip to content

Commit f81d7ef

Browse files
Revert "loading: refactor .ji loading, to handle errors better (#24630)"
This reverts commit 82fb32f.
1 parent 82fb32f commit f81d7ef

File tree

5 files changed

+107
-110
lines changed

5 files changed

+107
-110
lines changed

base/loading.jl

Lines changed: 34 additions & 62 deletions
Original file line numberDiff line numberDiff line change
@@ -118,58 +118,22 @@ end
118118

119119
# these return either the array of modules loaded from the path / content given
120120
# or an Exception that describes why it couldn't be loaded
121-
function _include_from_serialized(content::Vector{UInt8}, depmods::Vector{Module})
122-
return ccall(:jl_restore_incremental_from_buf, Any, (Ptr{UInt8}, Int, Any), content, sizeof(content), depmods)
121+
function _include_from_serialized(content::Vector{UInt8})
122+
return ccall(:jl_restore_incremental_from_buf, Any, (Ptr{UInt8}, Int), content, sizeof(content))
123123
end
124-
function _include_from_serialized(path::String, depmods::Vector{Module})
125-
return ccall(:jl_restore_incremental, Any, (Cstring, Any), path, depmods)
124+
function _include_from_serialized(path::String)
125+
return ccall(:jl_restore_incremental, Any, (Cstring,), path)
126126
end
127127

128128
# returns an array of modules loaded, or an Exception that describes why it failed
129129
# and it reconnects the Base.Docs.META
130130
function _require_from_serialized(mod::Symbol, path_to_try::String)
131-
return _require_from_serialized(mod, path_to_try, parse_cache_header(path_to_try)[3])
132-
end
133-
function _require_from_serialized(mod::Symbol, path_to_try::String, depmodnames::Vector{Pair{Symbol, UInt64}})
134-
# load all of the dependent modules
135-
ndeps = length(depmodnames)
136-
depmods = Vector{Module}(uninitialized, ndeps)
137-
for i in 1:ndeps
138-
modname, uuid = depmodnames[i]
139-
if root_module_exists(modname)
140-
M = root_module(modname)
141-
if module_name(M) === modname && module_uuid(M) === uuid
142-
depmods[i] = M
143-
end
144-
else
145-
modpath = find_package(string(modname))
146-
modpath === nothing && return ErrorException("Required dependency $modname not found in current path.")
147-
mod = _require_search_from_serialized(modname, String(modpath))
148-
if !isa(mod, Bool)
149-
for M in mod::Vector{Any}
150-
if module_name(M) === modname && module_uuid(M) === uuid
151-
depmods[i] = M
152-
break
153-
end
154-
end
155-
for callback in package_callbacks
156-
invokelatest(callback, modname)
157-
end
158-
end
159-
end
160-
isassigned(depmods, i) || return ErrorException("Required dependency $modname failed to load from a cache file.")
161-
end
162-
# now load the path_to_try.ji file
163-
restored = _include_from_serialized(path_to_try, depmods)
131+
restored = _include_from_serialized(path_to_try)
164132
if !isa(restored, Exception)
165133
for M in restored::Vector{Any}
166-
M = M::Module
167134
if isdefined(M, Base.Docs.META)
168135
push!(Base.Docs.modules, M)
169136
end
170-
if module_parent(M) === M
171-
register_root_module(module_name(M), M)
172-
end
173137
end
174138
end
175139
return restored
@@ -181,13 +145,12 @@ end
181145
function _require_search_from_serialized(mod::Symbol, sourcepath::String)
182146
paths = find_all_in_cache_path(mod)
183147
for path_to_try in paths::Vector{String}
184-
deps = stale_cachefile(sourcepath, path_to_try)
185-
if deps === true
148+
if stale_cachefile(sourcepath, path_to_try)
186149
continue
187150
end
188-
restored = _require_from_serialized(mod, path_to_try, deps)
151+
restored = _require_from_serialized(mod, path_to_try)
189152
if isa(restored, Exception)
190-
if isa(restored, ErrorException)
153+
if isa(restored, ErrorException) && endswith(restored.msg, " uuid did not match cache file.")
191154
# can't use this cache due to a module uuid mismatch,
192155
# defer reporting error until after trying all of the possible matches
193156
DEBUG_LOADING[] && info("JL_DEBUG_LOADING: Failed to load $path_to_try because $(restored.msg)")
@@ -220,7 +183,7 @@ const package_callbacks = Any[]
220183
const include_callbacks = Any[]
221184

222185
# used to optionally track dependencies when requiring a module:
223-
const _concrete_dependencies = Pair{Symbol, UInt64}[] # these dependency versions are "set in stone", and the process should try to avoid invalidating them
186+
const _concrete_dependencies = Any[] # these dependency versions are "set in stone", and the process should try to avoid invalidating them
224187
const _require_dependencies = Any[] # a list of (mod, path, mtime) tuples that are the file dependencies of the module currently being precompiled
225188
const _track_dependencies = Ref(false) # set this to true to track the list of file dependencies
226189
function _include_dependency(modstring::AbstractString, _path::AbstractString)
@@ -400,6 +363,14 @@ function unreference_module(key)
400363
end
401364
end
402365

366+
function register_all(a)
367+
for m in a
368+
if module_parent(m) === m
369+
register_root_module(module_name(m), m)
370+
end
371+
end
372+
end
373+
403374
function _require(mod::Symbol)
404375
# dependency-tracking is only used for one top-level include(path),
405376
# and is not applied recursively to imported modules:
@@ -425,13 +396,13 @@ function _require(mod::Symbol)
425396
if path === nothing
426397
throw(ArgumentError("Module $name not found in current path.\nRun `Pkg.add(\"$name\")` to install the $name package."))
427398
end
428-
path = String(path)
429399

430400
# attempt to load the module file via the precompile cache locations
431401
doneprecompile = false
432402
if JLOptions().use_compiled_modules != 0
433403
doneprecompile = _require_search_from_serialized(mod, path)
434404
if !isa(doneprecompile, Bool)
405+
register_all(doneprecompile)
435406
return
436407
end
437408
end
@@ -459,6 +430,7 @@ function _require(mod::Symbol)
459430
warn(m, prefix="WARNING: ")
460431
# fall-through, TODO: disable __precompile__(true) error so that the normal include will succeed
461432
else
433+
register_all(m)
462434
return
463435
end
464436
end
@@ -480,6 +452,7 @@ function _require(mod::Symbol)
480452
# TODO: disable __precompile__(true) error and do normal include instead of error
481453
error("Module $mod declares __precompile__(true) but require failed to create a usable precompiled cache file.")
482454
end
455+
register_all(m)
483456
end
484457
finally
485458
toplevel_load[] = last
@@ -572,7 +545,7 @@ function evalfile(path::AbstractString, args::Vector{String}=String[])
572545
end
573546
evalfile(path::AbstractString, args::Vector) = evalfile(path, String[args...])
574547

575-
function create_expr_cache(input::String, output::String, concrete_deps::typeof(_concrete_dependencies))
548+
function create_expr_cache(input::String, output::String, concrete_deps::Vector{Any})
576549
rm(output, force=true) # Remove file if it exists
577550
code_object = """
578551
while !eof(STDIN)
@@ -639,12 +612,12 @@ function compilecache(name::String)
639612
if !isdir(cachepath)
640613
mkpath(cachepath)
641614
end
642-
cachefile::String = abspath(cachepath, "$name.ji")
615+
cachefile::String = abspath(cachepath, name*".ji")
643616
# build up the list of modules that we want the precompile process to preserve
644617
concrete_deps = copy(_concrete_dependencies)
645-
for (key, mod) in loaded_modules
618+
for (key,mod) in loaded_modules
646619
if !(mod === Main || mod === Core || mod === Base)
647-
push!(concrete_deps, key => module_uuid(mod))
620+
push!(concrete_deps, (key, module_uuid(mod)))
648621
end
649622
end
650623
# run the expression and cache the result
@@ -671,13 +644,13 @@ module_uuid(m::Module) = ccall(:jl_module_uuid, UInt64, (Any,), m)
671644
isvalid_cache_header(f::IOStream) = 0 != ccall(:jl_read_verify_header, Cint, (Ptr{Void},), f.ios)
672645

673646
function parse_cache_header(f::IO)
674-
modules = Vector{Pair{Symbol, UInt64}}()
647+
modules = Dict{Symbol,UInt64}()
675648
while true
676649
n = ntoh(read(f, Int32))
677650
n == 0 && break
678651
sym = Symbol(read(f, n)) # module symbol
679652
uuid = ntoh(read(f, UInt64)) # module UUID (mostly just a timestamp)
680-
push!(modules, sym => uuid)
653+
modules[sym] = uuid
681654
end
682655
totbytes = ntoh(read(f, Int64)) # total bytes for file dependencies
683656
# read the list of files
@@ -696,13 +669,13 @@ function parse_cache_header(f::IO)
696669
@assert totbytes == 12 "header of cache file appears to be corrupt"
697670
srctextpos = ntoh(read(f, Int64))
698671
# read the list of modules that are required to be present during loading
699-
required_modules = Vector{Pair{Symbol, UInt64}}()
672+
required_modules = Dict{Symbol,UInt64}()
700673
while true
701674
n = ntoh(read(f, Int32))
702675
n == 0 && break
703676
sym = Symbol(read(f, n)) # module symbol
704677
uuid = ntoh(read(f, UInt64)) # module UUID
705-
push!(required_modules, sym => uuid)
678+
required_modules[sym] = uuid
706679
end
707680
return modules, files, required_modules, srctextpos
708681
end
@@ -763,8 +736,6 @@ function read_dependency_src(cachefile::String, filename::AbstractString)
763736
end
764737
end
765738

766-
# returns true if it "cachefile.ji" is stale relative to "modpath.jl"
767-
# otherwise returns the list of dependencies to also check
768739
function stale_cachefile(modpath::String, cachefile::String)
769740
io = open(cachefile, "r")
770741
try
@@ -773,12 +744,13 @@ function stale_cachefile(modpath::String, cachefile::String)
773744
return true # invalid cache file
774745
end
775746
modules, files, required_modules = parse_cache_header(io)
776-
modules = Dict{Symbol, UInt64}(modules)
777747

778748
# Check if transitive dependencies can be fullfilled
779-
for (mod, uuid_req) in required_modules
749+
for mod in keys(required_modules)
750+
if mod == :Main || mod == :Core || mod == :Base
751+
continue
780752
# Module is already loaded
781-
if root_module_exists(mod)
753+
elseif root_module_exists(mod)
782754
continue
783755
end
784756
name = string(mod)
@@ -796,7 +768,7 @@ function stale_cachefile(modpath::String, cachefile::String)
796768
uuid = get(modules, mod, UInt64(0))
797769
if uuid !== UInt64(0)
798770
if uuid === uuid_req
799-
return required_modules # this is the file we want
771+
return false # this is the file we want
800772
end
801773
DEBUG_LOADING[] && info("JL_DEBUG_LOADING: Rejecting cache file $cachefile because it provides the wrong uuid (got $uuid) for $mod (want $uuid_req).")
802774
return true # cachefile doesn't provide the required version of the dependency
@@ -825,7 +797,7 @@ function stale_cachefile(modpath::String, cachefile::String)
825797
return true
826798
end
827799

828-
return required_modules # fresh cachefile
800+
return false # fresh cachefile
829801
finally
830802
close(io)
831803
end

base/precompile.jl

Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -1681,7 +1681,7 @@ precompile(Tuple{typeof(Base.collect_to!), Array{Int32, 1}, Base.Generator{Array
16811681
precompile(Tuple{typeof(Base.collect_to!), Array{Symbol, 1}, Base.Generator{Array{Any, 1}, typeof(Base.FastMath.make_fastmath)}, Int64, Int64})
16821682
precompile(Tuple{typeof(Base.compilecache), String})
16831683
precompile(Tuple{typeof(Base.copy!), Array{Tuple{String, Float64}, 1}, Int64, Array{Tuple{String, Float64}, 1}, Int64, Int64})
1684-
precompile(Tuple{typeof(Base.create_expr_cache), String, String, typeof(Base._concrete_dependencies)})
1684+
precompile(Tuple{typeof(Base.create_expr_cache), String, String, Array{Any, 1}})
16851685
precompile(Tuple{typeof(Base._delete!), Base.Dict{Symbol, Base.Condition}, Int64})
16861686
precompile(Tuple{typeof(Base.Distributed.flush_gc_msgs), Base.Distributed.Worker})
16871687
precompile(Tuple{typeof(Base.Distributed.remote_do), typeof(Base.exit), Base.Distributed.Worker})
@@ -1722,7 +1722,7 @@ precompile(Tuple{typeof(Base.ht_keyindex), Base.Dict{Tuple{String, Float64}, Voi
17221722
precompile(Tuple{typeof(Base.ht_keyindex), Base.Dict{WeakRef, Void}, Base.Distributed.Future})
17231723
precompile(Tuple{typeof(Base.ident_cmp), Tuple{String, String, Int64}, Tuple{String, Int64}})
17241724
precompile(Tuple{typeof(Base.include_relative), String})
1725-
precompile(Tuple{typeof(Base._include_from_serialized), String, Vector{Module}})
1725+
precompile(Tuple{typeof(Base._include_from_serialized), String})
17261726
precompile(Tuple{typeof(Base.indexed_next), Tuple{Symbol, UInt64}, Int64, Int64})
17271727
precompile(Tuple{typeof(Base.indexed_next), Tuple{Void, Void}, Int64, Int64})
17281728
precompile(Tuple{typeof(Base.isassigned), Array{String, 1}, Int64})
@@ -1763,7 +1763,7 @@ precompile(Tuple{typeof(Base.rehash!), Base.Dict{Symbol, Base.Condition}, Int64}
17631763
precompile(Tuple{typeof(Base.rehash!), Base.Dict{Symbol, UInt64}, Int64})
17641764
precompile(Tuple{typeof(Base.rehash!), Base.Dict{Tuple{String, Float64}, Void}, Int64})
17651765
precompile(Tuple{typeof(Base.remove_linenums!), Module})
1766-
precompile(Tuple{typeof(Base._require_from_serialized), Symbol, String, Vector{Pair{Symbol, UInt64}}})
1766+
precompile(Tuple{typeof(Base._require_from_serialized), Symbol, String})
17671767
precompile(Tuple{typeof(Base._require_search_from_serialized), Symbol, String})
17681768
precompile(Tuple{typeof(Base.require), Symbol})
17691769
precompile(Tuple{typeof(Base.resize!), Array{Base.Condition, 1}, Int64})

src/dump.c

Lines changed: 45 additions & 20 deletions
Original file line numberDiff line numberDiff line change
@@ -1924,29 +1924,53 @@ static int size_isgreater(const void *a, const void *b)
19241924
return *(size_t*)b - *(size_t*)a;
19251925
}
19261926

1927-
static jl_value_t *read_verify_mod_list(ios_t *s, arraylist_t *dependent_worlds, jl_array_t *mod_list)
1927+
static jl_value_t *read_verify_mod_list(ios_t *s, arraylist_t *dependent_worlds)
19281928
{
19291929
if (!jl_main_module->uuid) {
19301930
return jl_get_exceptionf(jl_errorexception_type,
19311931
"Main module uuid state is invalid for module deserialization.");
19321932
}
1933-
size_t i, l = jl_array_len(mod_list);
1934-
for (i = 0; ; i++) {
1933+
jl_array_t *mod_array = jl_alloc_vec_any(0);
1934+
JL_GC_PUSH1(&mod_array);
1935+
while (1) {
19351936
size_t len = read_int32(s);
1936-
if (len == 0 && i == l)
1937-
return NULL; // success
1938-
if (len == 0 || i == l)
1939-
return jl_get_exceptionf(jl_errorexception_type, "Wrong number of entries in module list.");
1940-
char *name = (char*)alloca(len + 1);
1937+
if (len == 0) {
1938+
JL_GC_POP();
1939+
return (jl_value_t*)mod_array;
1940+
}
1941+
char *name = (char*)alloca(len+1);
19411942
ios_read(s, name, len);
19421943
name[len] = '\0';
19431944
uint64_t uuid = read_uint64(s);
1944-
jl_sym_t *sym = jl_symbol_n(name, len);
1945-
jl_module_t *m = (jl_module_t*)jl_array_ptr_ref(mod_list, i);
1946-
if (!m || !jl_is_module(m) || m->name != sym || m->uuid != uuid) {
1945+
jl_sym_t *sym = jl_symbol(name);
1946+
jl_module_t *m = NULL;
1947+
static jl_value_t *require_func = NULL;
1948+
if (!require_func)
1949+
require_func = jl_get_global(jl_base_module, jl_symbol("require"));
1950+
jl_value_t *reqargs[2] = {require_func, (jl_value_t*)sym};
1951+
JL_TRY {
1952+
m = (jl_module_t*)jl_apply(reqargs, 2);
1953+
}
1954+
JL_CATCH {
1955+
ios_close(s);
1956+
jl_rethrow();
1957+
}
1958+
if (!m) {
1959+
JL_GC_POP();
1960+
return jl_get_exceptionf(jl_errorexception_type,
1961+
"Requiring \"%s\" did not define a corresponding module.", name);
1962+
}
1963+
if (!jl_is_module(m)) {
1964+
JL_GC_POP();
1965+
return jl_get_exceptionf(jl_errorexception_type,
1966+
"Invalid module path (%s does not name a module).", name);
1967+
}
1968+
if (m->uuid != uuid) {
1969+
JL_GC_POP();
19471970
return jl_get_exceptionf(jl_errorexception_type,
1948-
"Invalid input in module list: expected %s.", name);
1971+
"Module %s uuid did not match cache file.", name);
19491972
}
1973+
jl_array_ptr_1d_push(mod_array, (jl_value_t*)m);
19501974
if (m->primary_world > jl_main_module->primary_world)
19511975
arraylist_push(dependent_worlds, (void*)m->primary_world);
19521976
}
@@ -2635,7 +2659,7 @@ static int trace_method(jl_typemap_entry_t *entry, void *closure)
26352659
return 1;
26362660
}
26372661

2638-
static jl_value_t *_jl_restore_incremental(ios_t *f, jl_array_t *mod_array)
2662+
static jl_value_t *_jl_restore_incremental(ios_t *f)
26392663
{
26402664
jl_ptls_t ptls = jl_get_ptls_states();
26412665
if (ios_eof(f) || !jl_read_verify_header(f)) {
@@ -2658,12 +2682,13 @@ static jl_value_t *_jl_restore_incremental(ios_t *f, jl_array_t *mod_array)
26582682
arraylist_new(&dependent_worlds, 0);
26592683

26602684
// verify that the system state is valid
2661-
jl_value_t *verify_fail = read_verify_mod_list(f, &dependent_worlds, mod_array);
2662-
if (verify_fail) {
2685+
jl_value_t *verify_result = read_verify_mod_list(f, &dependent_worlds);
2686+
if (!jl_is_array(verify_result)) {
26632687
arraylist_free(&dependent_worlds);
26642688
ios_close(f);
2665-
return verify_fail;
2689+
return verify_result;
26662690
}
2691+
jl_array_t *mod_array = (jl_array_t*)verify_result;
26672692

26682693
// prepare to deserialize
26692694
int en = jl_gc_enable(0);
@@ -2726,21 +2751,21 @@ static jl_value_t *_jl_restore_incremental(ios_t *f, jl_array_t *mod_array)
27262751
return (jl_value_t*)restored;
27272752
}
27282753

2729-
JL_DLLEXPORT jl_value_t *jl_restore_incremental_from_buf(const char *buf, size_t sz, jl_array_t *mod_array)
2754+
JL_DLLEXPORT jl_value_t *jl_restore_incremental_from_buf(const char *buf, size_t sz)
27302755
{
27312756
ios_t f;
27322757
ios_static_buffer(&f, (char*)buf, sz);
2733-
return _jl_restore_incremental(&f, mod_array);
2758+
return _jl_restore_incremental(&f);
27342759
}
27352760

2736-
JL_DLLEXPORT jl_value_t *jl_restore_incremental(const char *fname, jl_array_t *mod_array)
2761+
JL_DLLEXPORT jl_value_t *jl_restore_incremental(const char *fname)
27372762
{
27382763
ios_t f;
27392764
if (ios_file(&f, fname, 1, 0, 0, 0) == NULL) {
27402765
return jl_get_exceptionf(jl_errorexception_type,
27412766
"Cache file \"%s\" not found.\n", fname);
27422767
}
2743-
return _jl_restore_incremental(&f, mod_array);
2768+
return _jl_restore_incremental(&f);
27442769
}
27452770

27462771
// --- init ---

src/julia.h

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1381,8 +1381,8 @@ JL_DLLEXPORT void jl_save_system_image(const char *fname);
13811381
JL_DLLEXPORT void jl_restore_system_image(const char *fname);
13821382
JL_DLLEXPORT void jl_restore_system_image_data(const char *buf, size_t len);
13831383
JL_DLLEXPORT int jl_save_incremental(const char *fname, jl_array_t *worklist);
1384-
JL_DLLEXPORT jl_value_t *jl_restore_incremental(const char *fname, jl_array_t *depmods);
1385-
JL_DLLEXPORT jl_value_t *jl_restore_incremental_from_buf(const char *buf, size_t sz, jl_array_t *depmods);
1384+
JL_DLLEXPORT jl_value_t *jl_restore_incremental(const char *fname);
1385+
JL_DLLEXPORT jl_value_t *jl_restore_incremental_from_buf(const char *buf, size_t sz);
13861386

13871387
// front end interface
13881388
JL_DLLEXPORT jl_value_t *jl_parse_input_line(const char *str, size_t len,

0 commit comments

Comments
 (0)