@@ -260,7 +260,7 @@ struct LoadingCache
260260    identified:: Dict{String, Union{Nothing, Tuple{PkgId, String}}} 
261261    located:: Dict{Tuple{PkgId, Union{String, Nothing}}, Union{Tuple{String, String}, Nothing}} 
262262end 
263- const  LOADING_CACHE =  Ref {Union{LoadingCache, Nothing}} (nothing )
263+ const  LOADING_CACHE =  Ref {Union{LoadingCache, Nothing}} (nothing )  #  n.b.: all access to and through this are protected by require_lock 
264264LoadingCache () =  LoadingCache (load_path (), Dict (), Dict (), Dict (), Set (), Dict (), Dict (), Dict ())
265265
266266
@@ -302,10 +302,12 @@ end
302302
303303#  Used by Pkg but not used in loading itself
304304function  find_package (arg) #  ::Union{Nothing,String}
305+     @lock  require_lock begin 
305306    pkgenv =  identify_package_env (arg)
306307    pkgenv ===  nothing  &&  return  nothing 
307308    pkg, env =  pkgenv
308309    return  locate_package (pkg, env)
310+     end 
309311end 
310312
311313#  is there a better/faster ground truth?
@@ -332,6 +334,7 @@ is also returned, except when the identity is not identified.
332334""" 
333335identify_package_env (where :: Module , name:: String ) =  identify_package_env (PkgId (where ), name)
334336function  identify_package_env (where :: PkgId , name:: String )
337+     assert_havelock (require_lock)
335338    cache =  LOADING_CACHE[]
336339    if  cache != =  nothing 
337340        pkg_env =  get (cache. identified_where, (where , name), missing )
@@ -364,6 +367,7 @@ function identify_package_env(where::PkgId, name::String)
364367    return  pkg_env
365368end 
366369function  identify_package_env (name:: String )
370+     assert_havelock (require_lock)
367371    cache =  LOADING_CACHE[]
368372    if  cache != =  nothing 
369373        pkg_env =  get (cache. identified, name, missing )
@@ -426,11 +430,12 @@ julia> using LinearAlgebra
426430julia> Base.identify_package(LinearAlgebra, "Pkg") # Pkg is not a dependency of LinearAlgebra 
427431``` 
428432""" 
429- identify_package (where :: Module , name:: String ) =  _nothing_or_first (identify_package_env (where , name))
430- identify_package (where :: PkgId , name:: String )  =  _nothing_or_first (identify_package_env (where , name))
431- identify_package (name:: String )                =  _nothing_or_first (identify_package_env (name))
433+ identify_package (where :: Module , name:: String ) =  @lock  require_lock  _nothing_or_first (identify_package_env (where , name))
434+ identify_package (where :: PkgId , name:: String )  =  @lock  require_lock  _nothing_or_first (identify_package_env (where , name))
435+ identify_package (name:: String )                =  @lock  require_lock  _nothing_or_first (identify_package_env (name))
432436
433437function  locate_package_env (pkg:: PkgId , stopenv:: Union{String, Nothing} = nothing ):: Union{Nothing,Tuple{String,String}} 
438+     assert_havelock (require_lock)
434439    cache =  LOADING_CACHE[]
435440    if  cache != =  nothing 
436441        pathenv =  get (cache. located, (pkg, stopenv), missing )
@@ -508,7 +513,7 @@ julia> Base.locate_package(pkg)
508513``` 
509514""" 
510515function  locate_package (pkg:: PkgId , stopenv:: Union{String, Nothing} = nothing ):: Union{Nothing,String} 
511-     _nothing_or_first (locate_package_env (pkg, stopenv))
516+     @lock  require_lock  _nothing_or_first (locate_package_env (pkg, stopenv))
512517end 
513518
514519""" 
@@ -1824,51 +1829,60 @@ function show(io::IO, it::ImageTarget)
18241829end 
18251830
18261831#  should sync with the types of arguments of `stale_cachefile`
1827- const  StaleCacheKey =  Tuple{PkgId, UInt128, String, String}
1832+ const  StaleCacheKey =  Tuple{PkgId, UInt128, String, String, Bool, CacheFlags }
18281833
1829- function  compilecache_path (pkg:: PkgId ;
1834+ function  compilecache_freshest_path (pkg:: PkgId ;
18301835        ignore_loaded:: Bool = false ,
18311836        stale_cache:: Dict{StaleCacheKey,Bool} = Dict {StaleCacheKey, Bool} (),
18321837        cachepath_cache:: Dict{PkgId, Vector{String}} = Dict {PkgId, Vector{String}} (),
1833-         cachepaths:: Vector{String} = get!  (() ->  find_all_in_cache_path (pkg), cachepath_cache, pkg),
1838+         cachepaths:: Vector{String} = get (() ->  find_all_in_cache_path (pkg), cachepath_cache, pkg),
18341839        sourcepath:: Union{String,Nothing} = Base. locate_package (pkg),
18351840        flags:: CacheFlags = CacheFlags ())
1836-     path =  nothing 
18371841    isnothing (sourcepath) &&  error (" Cannot locate source for $(repr (" text/plain"  " 
1838-     for  path_to_try in  cachepaths
1839-         staledeps =  stale_cachefile (sourcepath, path_to_try; ignore_loaded, requested_flags= flags)
1840-         if  staledeps ===  true 
1841-             continue 
1842-         end 
1843-         staledeps, _, _ =  staledeps:: Tuple{Vector{Any}, Union{Nothing, String}, UInt128} 
1844-         #  finish checking staledeps module graph
1845-         for  dep in  staledeps
1846-             dep isa  Module &&  continue 
1847-             modpath, modkey, modbuild_id =  dep:: Tuple{String, PkgId, UInt128} 
1848-             modpaths =  get! (() ->  find_all_in_cache_path (modkey), cachepath_cache, modkey)
1849-             for  modpath_to_try in  modpaths:: Vector{String} 
1850-                 stale_cache_key =  (modkey, modbuild_id, modpath, modpath_to_try):: StaleCacheKey 
1851-                 if  get! (() ->  stale_cachefile (stale_cache_key... ; ignore_loaded, requested_flags= flags) ===  true ,
1852-                         stale_cache, stale_cache_key)
1853-                     continue 
1842+     try_build_ids =  UInt128[UInt128 (0 )]
1843+     if  ! ignore_loaded
1844+         let  loaded =  get (loaded_precompiles, pkg, nothing )
1845+             if  loaded != =  nothing 
1846+                 for  mod in  loaded #  try these in reverse original load order to see if one is already valid
1847+                     pushfirst! (try_build_ids, module_build_id (mod))
18541848                end 
1855-                 @goto  check_next_dep
18561849            end 
1857-             @goto  check_next_path
1858-             @label  check_next_dep
18591850        end 
1860-         try 
1861-             #  update timestamp of precompilation file so that it is the first to be tried by code loading
1862-             touch (path_to_try)
1863-         catch  ex
1864-             #  file might be read-only and then we fail to update timestamp, which is fine
1865-             ex isa  IOError ||  rethrow ()
1851+     end 
1852+     for  build_id in  try_build_ids
1853+         for  path_to_try in  cachepaths
1854+             staledeps =  stale_cachefile (pkg, build_id, sourcepath, path_to_try; ignore_loaded, requested_flags= flags)
1855+             if  staledeps ===  true 
1856+                 continue 
1857+             end 
1858+             staledeps, _, _ =  staledeps:: Tuple{Vector{Any}, Union{Nothing, String}, UInt128} 
1859+             #  finish checking staledeps module graph
1860+             for  dep in  staledeps
1861+                 dep isa  Module &&  continue 
1862+                 modpath, modkey, modbuild_id =  dep:: Tuple{String, PkgId, UInt128} 
1863+                 modpaths =  get (() ->  find_all_in_cache_path (modkey), cachepath_cache, modkey)
1864+                 for  modpath_to_try in  modpaths:: Vector{String} 
1865+                     stale_cache_key =  (modkey, modbuild_id, modpath, modpath_to_try, ignore_loaded, flags):: StaleCacheKey 
1866+                     if  get! (() ->  stale_cachefile (modkey, modbuild_id, modpath, modpath_to_try; ignore_loaded, requested_flags= flags) ===  true ,
1867+                             stale_cache, stale_cache_key)
1868+                         continue 
1869+                     end 
1870+                     @goto  check_next_dep
1871+                 end 
1872+                 @goto  check_next_path
1873+                 @label  check_next_dep
1874+             end 
1875+             try 
1876+                 #  update timestamp of precompilation file so that it is the first to be tried by code loading
1877+                 touch (path_to_try)
1878+             catch  ex
1879+                 #  file might be read-only and then we fail to update timestamp, which is fine
1880+                 ex isa  IOError ||  rethrow ()
1881+             end 
1882+             return  path_to_try
1883+             @label  check_next_path
18661884        end 
1867-         path =  path_to_try
1868-         break 
1869-         @label  check_next_path
18701885    end 
1871-     return  path
18721886end 
18731887
18741888""" 
@@ -1884,14 +1898,8 @@ fresh julia session specify `ignore_loaded=true`.
18841898!!! compat "Julia 1.10" 
18851899    This function requires at least Julia 1.10. 
18861900""" 
1887- function  isprecompiled (pkg:: PkgId ;
1888-         ignore_loaded:: Bool = false ,
1889-         stale_cache:: Dict{StaleCacheKey,Bool} = Dict {StaleCacheKey, Bool} (),
1890-         cachepath_cache:: Dict{PkgId, Vector{String}} = Dict {PkgId, Vector{String}} (),
1891-         cachepaths:: Vector{String} = get! (() ->  find_all_in_cache_path (pkg), cachepath_cache, pkg),
1892-         sourcepath:: Union{String,Nothing} = Base. locate_package (pkg),
1893-         flags:: CacheFlags = CacheFlags ())
1894-     path =  compilecache_path (pkg; ignore_loaded, stale_cache, cachepath_cache, cachepaths, sourcepath, flags)
1901+ function  isprecompiled (pkg:: PkgId ; ignore_loaded:: Bool = false )
1902+     path =  compilecache_freshest_path (pkg; ignore_loaded)
18951903    return  ! isnothing (path)
18961904end 
18971905
@@ -1905,7 +1913,7 @@ associated cache is relocatable.
19051913    This function requires at least Julia 1.11. 
19061914""" 
19071915function  isrelocatable (pkg:: PkgId )
1908-     path =  compilecache_path (pkg)
1916+     path =  compilecache_freshest_path (pkg)
19091917    isnothing (path) &&  return  false 
19101918    io =  open (path, " r" 
19111919    try 
@@ -1925,6 +1933,23 @@ function isrelocatable(pkg::PkgId)
19251933    return  true 
19261934end 
19271935
1936+ function  parse_cache_buildid (cachepath:: String )
1937+     f =  open (cachepath, " r" 
1938+     try 
1939+         checksum =  isvalid_cache_header (f)
1940+         iszero (checksum) &&  throw (ArgumentError (" Incompatible header in cache file $cachefile ." 
1941+         flags =  read (f, UInt8)
1942+         n =  read (f, Int32)
1943+         n ==  0  &&  error (" no module defined in $cachefile " 
1944+         skip (f, n) #  module name
1945+         uuid =  UUID ((read (f, UInt64), read (f, UInt64))) #  pkg UUID
1946+         build_id =  (UInt128 (checksum) <<  64 ) |  read (f, UInt64)
1947+         return  build_id, uuid
1948+     finally 
1949+         close (f)
1950+     end 
1951+ end 
1952+ 
19281953#  search for a precompile cache file to load, after some various checks
19291954function  _tryrequire_from_serialized (modkey:: PkgId , build_id:: UInt128 )
19301955    assert_havelock (require_lock)
@@ -2682,8 +2707,19 @@ function __require_prelocked(pkg::PkgId, env)
26822707                    try 
26832708                        if  ! generating_output () &&  ! parallel_precompile_attempted &&  ! disable_parallel_precompile &&  @isdefined (Precompilation)
26842709                            parallel_precompile_attempted =  true 
2685-                             Precompilation. precompilepkgs ([pkg]; _from_loading= true , ignore_loaded= false )
2686-                             return 
2710+                             precompiled =  Precompilation. precompilepkgs ([pkg]; _from_loading= true , ignore_loaded= false )
2711+                             #  prcompiled returns either nothing, indicating it needs serial precompile,
2712+                             #  or the entry(ies) that it found would be best to load (possibly because it just created it)
2713+                             #  or an empty set of entries (indicating the precompile should be skipped)
2714+                             if  precompiled != =  nothing 
2715+                                 isempty (precompiled) &&  return  PrecompilableError () #  oops, Precompilation forgot to report what this might actually be
2716+                                 local  cachefile =  precompiled[1 ]
2717+                                 local  ocachefile =  nothing 
2718+                                 if  JLOptions (). use_pkgimages ==  1 
2719+                                     ocachefile =  ocachefile_from_cachefile (cachefile)
2720+                                 end 
2721+                                 return  cachefile, ocachefile
2722+                             end 
26872723                        end 
26882724                        triggers =  get (EXT_PRIMED, pkg, nothing )
26892725                        loadable_exts =  nothing 
0 commit comments