Skip to content

Commit 9c0f1dc

Browse files
authored
add being able to pass a CacheFlags() to isprecompiled to verify a precompile file against a set of custom flags (#53332)
1 parent 59102aa commit 9c0f1dc

File tree

5 files changed

+168
-142
lines changed

5 files changed

+168
-142
lines changed

base/loading.jl

Lines changed: 139 additions & 129 deletions
Original file line numberDiff line numberDiff line change
@@ -1495,6 +1495,126 @@ end
14951495

14961496
# End extensions
14971497

1498+
1499+
struct CacheFlags
1500+
# OOICCDDP - see jl_cache_flags
1501+
use_pkgimages::Bool
1502+
debug_level::Int
1503+
check_bounds::Int
1504+
inline::Bool
1505+
opt_level::Int
1506+
end
1507+
function CacheFlags(f::UInt8)
1508+
use_pkgimages = Bool(f & 1)
1509+
debug_level = Int((f >> 1) & 3)
1510+
check_bounds = Int((f >> 3) & 3)
1511+
inline = Bool((f >> 5) & 1)
1512+
opt_level = Int((f >> 6) & 3) # define OPT_LEVEL in statiddata_utils
1513+
CacheFlags(use_pkgimages, debug_level, check_bounds, inline, opt_level)
1514+
end
1515+
CacheFlags(f::Int) = CacheFlags(UInt8(f))
1516+
CacheFlags() = CacheFlags(ccall(:jl_cache_flags, UInt8, ()))
1517+
1518+
function _cacheflag_to_uint8(cf::CacheFlags)::UInt8
1519+
f = UInt8(0)
1520+
f |= cf.use_pkgimages << 0
1521+
f |= cf.debug_level << 1
1522+
f |= cf.check_bounds << 3
1523+
f |= cf.inline << 5
1524+
f |= cf.opt_level << 6
1525+
return f
1526+
end
1527+
1528+
function show(io::IO, cf::CacheFlags)
1529+
print(io, "use_pkgimages = ", cf.use_pkgimages)
1530+
print(io, ", debug_level = ", cf.debug_level)
1531+
print(io, ", check_bounds = ", cf.check_bounds)
1532+
print(io, ", inline = ", cf.inline)
1533+
print(io, ", opt_level = ", cf.opt_level)
1534+
end
1535+
1536+
struct ImageTarget
1537+
name::String
1538+
flags::Int32
1539+
ext_features::String
1540+
features_en::Vector{UInt8}
1541+
features_dis::Vector{UInt8}
1542+
end
1543+
1544+
function parse_image_target(io::IO)
1545+
flags = read(io, Int32)
1546+
nfeature = read(io, Int32)
1547+
feature_en = read(io, 4*nfeature)
1548+
feature_dis = read(io, 4*nfeature)
1549+
name_len = read(io, Int32)
1550+
name = String(read(io, name_len))
1551+
ext_features_len = read(io, Int32)
1552+
ext_features = String(read(io, ext_features_len))
1553+
ImageTarget(name, flags, ext_features, feature_en, feature_dis)
1554+
end
1555+
1556+
function parse_image_targets(targets::Vector{UInt8})
1557+
io = IOBuffer(targets)
1558+
ntargets = read(io, Int32)
1559+
targets = Vector{ImageTarget}(undef, ntargets)
1560+
for i in 1:ntargets
1561+
targets[i] = parse_image_target(io)
1562+
end
1563+
return targets
1564+
end
1565+
1566+
function current_image_targets()
1567+
targets = @ccall jl_reflect_clone_targets()::Vector{UInt8}
1568+
return parse_image_targets(targets)
1569+
end
1570+
1571+
struct FeatureName
1572+
name::Cstring
1573+
bit::UInt32 # bit index into a `uint32_t` array;
1574+
llvmver::UInt32 # 0 if it is available on the oldest LLVM version we support
1575+
end
1576+
1577+
function feature_names()
1578+
fnames = Ref{Ptr{FeatureName}}()
1579+
nf = Ref{Csize_t}()
1580+
@ccall jl_reflect_feature_names(fnames::Ptr{Ptr{FeatureName}}, nf::Ptr{Csize_t})::Cvoid
1581+
if fnames[] == C_NULL
1582+
@assert nf[] == 0
1583+
return Vector{FeatureName}(undef, 0)
1584+
end
1585+
Base.unsafe_wrap(Array, fnames[], nf[], own=false)
1586+
end
1587+
1588+
function test_feature(features::Vector{UInt8}, feat::FeatureName)
1589+
bitidx = feat.bit
1590+
u8idx = div(bitidx, 8) + 1
1591+
bit = bitidx % 8
1592+
return (features[u8idx] & (1 << bit)) != 0
1593+
end
1594+
1595+
function show(io::IO, it::ImageTarget)
1596+
print(io, it.name)
1597+
if !isempty(it.ext_features)
1598+
print(io, ",", it.ext_features)
1599+
end
1600+
print(io, "; flags=", it.flags)
1601+
print(io, "; features_en=(")
1602+
first = true
1603+
for feat in feature_names()
1604+
if test_feature(it.features_en, feat)
1605+
name = Base.unsafe_string(feat.name)
1606+
if first
1607+
first = false
1608+
print(io, name)
1609+
else
1610+
print(io, ", ", name)
1611+
end
1612+
end
1613+
end
1614+
print(io, ")")
1615+
# Is feature_dis useful?
1616+
end
1617+
14981618
# should sync with the types of arguments of `stale_cachefile`
14991619
const StaleCacheKey = Tuple{Base.PkgId, UInt128, String, String}
15001620

@@ -1515,11 +1635,11 @@ function isprecompiled(pkg::PkgId;
15151635
ignore_loaded::Bool=false,
15161636
stale_cache::Dict{StaleCacheKey,Bool}=Dict{StaleCacheKey, Bool}(),
15171637
cachepaths::Vector{String}=Base.find_all_in_cache_path(pkg),
1518-
sourcepath::Union{String,Nothing}=Base.locate_package(pkg)
1519-
)
1638+
sourcepath::Union{String,Nothing}=Base.locate_package(pkg),
1639+
flags::CacheFlags=CacheFlags())
15201640
isnothing(sourcepath) && error("Cannot locate source for $(repr(pkg))")
15211641
for path_to_try in cachepaths
1522-
staledeps = stale_cachefile(sourcepath, path_to_try, ignore_loaded = true)
1642+
staledeps = stale_cachefile(sourcepath, path_to_try, ignore_loaded = true, requested_flags=flags)
15231643
if staledeps === true
15241644
continue
15251645
end
@@ -1532,7 +1652,7 @@ function isprecompiled(pkg::PkgId;
15321652
modpaths = find_all_in_cache_path(modkey)
15331653
for modpath_to_try in modpaths::Vector{String}
15341654
stale_cache_key = (modkey, modbuild_id, modpath, modpath_to_try)::StaleCacheKey
1535-
if get!(() -> stale_cachefile(stale_cache_key...; ignore_loaded) === true,
1655+
if get!(() -> stale_cachefile(stale_cache_key...; ignore_loaded, requested_flags=flags) === true,
15361656
stale_cache, stale_cache_key)
15371657
continue
15381658
end
@@ -2535,8 +2655,7 @@ function create_expr_cache(pkg::PkgId, input::String, output::String, output_o::
25352655
if output_o !== nothing
25362656
@debug "Generating object cache file for $(repr("text/plain", pkg))"
25372657
cpu_target = get(ENV, "JULIA_CPU_TARGET", nothing)
2538-
opt_level = Base.JLOptions().opt_level
2539-
opts = `-O$(opt_level) --output-o $(output_o) --output-ji $(output) --output-incremental=yes`
2658+
opts = `--output-o $(output_o) --output-ji $(output) --output-incremental=yes`
25402659
else
25412660
@debug "Generating cache file for $(repr("text/plain", pkg))"
25422661
cpu_target = nothing
@@ -2546,10 +2665,11 @@ function create_expr_cache(pkg::PkgId, input::String, output::String, output_o::
25462665
deps_eltype = sprint(show, eltype(concrete_deps); context = :module=>nothing)
25472666
deps = deps_eltype * "[" * join(deps_strs, ",") * "]"
25482667
trace = isassigned(PRECOMPILE_TRACE_COMPILE) ? `--trace-compile=$(PRECOMPILE_TRACE_COMPILE[])` : ``
2549-
io = open(pipeline(addenv(`$(julia_cmd(;cpu_target)::Cmd) $(opts)
2668+
io = open(pipeline(addenv(`$(julia_cmd(;cpu_target)::Cmd)
2669+
$(flags)
2670+
$(opts)
25502671
--startup-file=no --history-file=no --warn-overwrite=yes
25512672
--color=$(have_color === nothing ? "auto" : have_color ? "yes" : "no")
2552-
$flags
25532673
$trace
25542674
-`,
25552675
"OPENBLAS_NUM_THREADS" => 1,
@@ -3212,116 +3332,6 @@ function check_clone_targets(clone_targets)
32123332
end
32133333
end
32143334

3215-
struct CacheFlags
3216-
# OOICCDDP - see jl_cache_flags
3217-
use_pkgimages::Bool
3218-
debug_level::Int
3219-
check_bounds::Int
3220-
inline::Bool
3221-
opt_level::Int
3222-
3223-
function CacheFlags(f::UInt8)
3224-
use_pkgimages = Bool(f & 1)
3225-
debug_level = Int((f >> 1) & 3)
3226-
check_bounds = Int((f >> 3) & 3)
3227-
inline = Bool((f >> 5) & 1)
3228-
opt_level = Int((f >> 6) & 3) # define OPT_LEVEL in statiddata_utils
3229-
new(use_pkgimages, debug_level, check_bounds, inline, opt_level)
3230-
end
3231-
end
3232-
CacheFlags(f::Int) = CacheFlags(UInt8(f))
3233-
CacheFlags() = CacheFlags(ccall(:jl_cache_flags, UInt8, ()))
3234-
3235-
function show(io::IO, cf::CacheFlags)
3236-
print(io, "use_pkgimages = ", cf.use_pkgimages)
3237-
print(io, ", debug_level = ", cf.debug_level)
3238-
print(io, ", check_bounds = ", cf.check_bounds)
3239-
print(io, ", inline = ", cf.inline)
3240-
print(io, ", opt_level = ", cf.opt_level)
3241-
end
3242-
3243-
struct ImageTarget
3244-
name::String
3245-
flags::Int32
3246-
ext_features::String
3247-
features_en::Vector{UInt8}
3248-
features_dis::Vector{UInt8}
3249-
end
3250-
3251-
function parse_image_target(io::IO)
3252-
flags = read(io, Int32)
3253-
nfeature = read(io, Int32)
3254-
feature_en = read(io, 4*nfeature)
3255-
feature_dis = read(io, 4*nfeature)
3256-
name_len = read(io, Int32)
3257-
name = String(read(io, name_len))
3258-
ext_features_len = read(io, Int32)
3259-
ext_features = String(read(io, ext_features_len))
3260-
ImageTarget(name, flags, ext_features, feature_en, feature_dis)
3261-
end
3262-
3263-
function parse_image_targets(targets::Vector{UInt8})
3264-
io = IOBuffer(targets)
3265-
ntargets = read(io, Int32)
3266-
targets = Vector{ImageTarget}(undef, ntargets)
3267-
for i in 1:ntargets
3268-
targets[i] = parse_image_target(io)
3269-
end
3270-
return targets
3271-
end
3272-
3273-
function current_image_targets()
3274-
targets = @ccall jl_reflect_clone_targets()::Vector{UInt8}
3275-
return parse_image_targets(targets)
3276-
end
3277-
3278-
struct FeatureName
3279-
name::Cstring
3280-
bit::UInt32 # bit index into a `uint32_t` array;
3281-
llvmver::UInt32 # 0 if it is available on the oldest LLVM version we support
3282-
end
3283-
3284-
function feature_names()
3285-
fnames = Ref{Ptr{FeatureName}}()
3286-
nf = Ref{Csize_t}()
3287-
@ccall jl_reflect_feature_names(fnames::Ptr{Ptr{FeatureName}}, nf::Ptr{Csize_t})::Cvoid
3288-
if fnames[] == C_NULL
3289-
@assert nf[] == 0
3290-
return Vector{FeatureName}(undef, 0)
3291-
end
3292-
Base.unsafe_wrap(Array, fnames[], nf[], own=false)
3293-
end
3294-
3295-
function test_feature(features::Vector{UInt8}, feat::FeatureName)
3296-
bitidx = feat.bit
3297-
u8idx = div(bitidx, 8) + 1
3298-
bit = bitidx % 8
3299-
return (features[u8idx] & (1 << bit)) != 0
3300-
end
3301-
3302-
function show(io::IO, it::ImageTarget)
3303-
print(io, it.name)
3304-
if !isempty(it.ext_features)
3305-
print(io, ",", it.ext_features)
3306-
end
3307-
print(io, "; flags=", it.flags)
3308-
print(io, "; features_en=(")
3309-
first = true
3310-
for feat in feature_names()
3311-
if test_feature(it.features_en, feat)
3312-
name = Base.unsafe_string(feat.name)
3313-
if first
3314-
first = false
3315-
print(io, name)
3316-
else
3317-
print(io, ", ", name)
3318-
end
3319-
end
3320-
end
3321-
print(io, ")")
3322-
# Is feature_dis useful?
3323-
end
3324-
33253335
# Set by FileWatching.__init__()
33263336
global mkpidlock_hook
33273337
global trymkpidlock_hook
@@ -3377,11 +3387,11 @@ list_reasons(::Nothing) = ""
33773387

33783388
# returns true if it "cachefile.ji" is stale relative to "modpath.jl" and build_id for modkey
33793389
# otherwise returns the list of dependencies to also check
3380-
@constprop :none function stale_cachefile(modpath::String, cachefile::String; ignore_loaded::Bool = false, reasons=nothing)
3381-
return stale_cachefile(PkgId(""), UInt128(0), modpath, cachefile; ignore_loaded, reasons)
3390+
@constprop :none function stale_cachefile(modpath::String, cachefile::String; ignore_loaded::Bool = false, requested_flags::CacheFlags=CacheFlags(), reasons=nothing)
3391+
return stale_cachefile(PkgId(""), UInt128(0), modpath, cachefile; ignore_loaded, requested_flags, reasons)
33823392
end
33833393
@constprop :none function stale_cachefile(modkey::PkgId, build_id::UInt128, modpath::String, cachefile::String;
3384-
ignore_loaded::Bool = false, reasons::Union{Dict{String,Int},Nothing}=nothing)
3394+
ignore_loaded::Bool = false, requested_flags::CacheFlags=CacheFlags(), reasons::Union{Dict{String,Int},Nothing}=nothing)
33853395
io = open(cachefile, "r")
33863396
try
33873397
checksum = isvalid_cache_header(io)
@@ -3390,15 +3400,15 @@ end
33903400
record_reason(reasons, "invalid header")
33913401
return true # invalid cache file
33923402
end
3393-
modules, (includes, _, requires), required_modules, srctextpos, prefs, prefs_hash, clone_targets, flags = parse_cache_header(io, cachefile)
3403+
modules, (includes, _, requires), required_modules, srctextpos, prefs, prefs_hash, clone_targets, actual_flags = parse_cache_header(io, cachefile)
33943404
if isempty(modules)
33953405
return true # ignore empty file
33963406
end
3397-
if ccall(:jl_match_cache_flags, UInt8, (UInt8,), flags) == 0
3407+
if @ccall(jl_match_cache_flags(_cacheflag_to_uint8(requested_flags)::UInt8, actual_flags::UInt8)::UInt8) == 0
33983408
@debug """
33993409
Rejecting cache file $cachefile for $modkey since the flags are mismatched
3400-
current session: $(CacheFlags())
3401-
cache file: $(CacheFlags(flags))
3410+
requested flags: $(requested_flags) [$(_cacheflag_to_uint8(requested_flags))]
3411+
cache file: $(CacheFlags(actual_flags)) [$actual_flags]
34023412
"""
34033413
record_reason(reasons, "mismatched flags")
34043414
return true
@@ -3672,7 +3682,7 @@ function precompile(@nospecialize(argt::Type), m::Method)
36723682
return precompile(mi)
36733683
end
36743684

3675-
precompile(include_package_for_output, (PkgId, String, Vector{String}, Vector{String}, Vector{String}, typeof(_concrete_dependencies), Nothing))
3676-
precompile(include_package_for_output, (PkgId, String, Vector{String}, Vector{String}, Vector{String}, typeof(_concrete_dependencies), String))
3677-
precompile(create_expr_cache, (PkgId, String, String, String, typeof(_concrete_dependencies), IO, IO, Cmd))
3678-
precompile(create_expr_cache, (PkgId, String, String, Nothing, typeof(_concrete_dependencies), IO, IO, Cmd))
3685+
@assert precompile(include_package_for_output, (PkgId, String, Vector{String}, Vector{String}, Vector{String}, typeof(_concrete_dependencies), Nothing))
3686+
@assert precompile(include_package_for_output, (PkgId, String, Vector{String}, Vector{String}, Vector{String}, typeof(_concrete_dependencies), String))
3687+
@assert precompile(create_expr_cache, (PkgId, String, String, String, typeof(_concrete_dependencies), Cmd, IO, IO))
3688+
@assert precompile(create_expr_cache, (PkgId, String, String, Nothing, typeof(_concrete_dependencies), Cmd, IO, IO))

src/jl_exported_funcs.inc

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -386,6 +386,7 @@
386386
XX(jl_raise_debugger) \
387387
XX(jl_readuntil) \
388388
XX(jl_cache_flags) \
389+
XX(jl_match_cache_flags_current) \
389390
XX(jl_match_cache_flags) \
390391
XX(jl_read_verify_header) \
391392
XX(jl_realloc) \

src/staticdata.c

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -3566,7 +3566,7 @@ static jl_value_t *jl_validate_cache_file(ios_t *f, jl_array_t *depmods, uint64_
35663566
"Precompile file header verification checks failed.");
35673567
}
35683568
uint8_t flags = read_uint8(f);
3569-
if (pkgimage && !jl_match_cache_flags(flags)) {
3569+
if (pkgimage && !jl_match_cache_flags_current(flags)) {
35703570
return jl_get_exceptionf(jl_errorexception_type, "Pkgimage flags mismatch");
35713571
}
35723572
if (!pkgimage) {

0 commit comments

Comments
 (0)