Skip to content

Commit d30adaf

Browse files
authored
Reduce footprint for invalidation (#1806)
This is a companion PR to JuliaLang/julia#35714 and accounts for a subset of the gains reported there. The more specific implementations of `==` and `hash` avoid a `collect`; that branch prevents many `collect`-induced invalidations via the `iteratorsize` trick, but this change is probably a good idea anyway. The more important and subtle one is the one in TOML._print. This is used by a large number of methods in Pkg, so it's important to prevent it from being invalidated. Do to nospecialize markers, this method gets inferred for partially- specified types, and the `a` is typically just `AbstractDict`. However, `Iterators.Pairs` is also an AbstractDict, and the return type of `keys` cannot be inferred from the parameters of `AbstractDict{K,V}` because the `itr` field of a pair uses a later parameter. This short-circuits the whole problem by "hand-inlining" the result of `invoke(keys, Tuple{AbstractDict})` at the call site, i.e., just creating a `KeySet` directly.
1 parent 6a95c0f commit d30adaf

File tree

2 files changed

+9
-3
lines changed

2 files changed

+9
-3
lines changed

ext/TOML/src/print.jl

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -57,7 +57,7 @@ function _print(io::IO, a::AbstractDict,
5757
sorted::Bool = false,
5858
by = identity,
5959
)
60-
akeys = keys(a)
60+
akeys = Base.KeySet(a) # keys is non-inferrable due to Iterators.Pairs
6161
if sorted
6262
akeys = sort!(collect(akeys), by = by)
6363
end

src/Types.jl

Lines changed: 8 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -227,8 +227,14 @@ Base.@kwdef mutable struct PackageEntry
227227
deps::Dict{String,UUID} = Dict{String,UUID}()
228228
other::Union{Dict,Nothing} = nothing
229229
end
230-
Base.:(==)(t1::PackageEntry, t2::PackageEntry) = all([getfield(t1, x) == getfield(t2, x) for x in filter!(!=(:other), collect(fieldnames(PackageEntry)))])
231-
Base.hash(x::PackageEntry, h::UInt) = foldr(hash, [getfield(t, x) for x in filter!(!=(:other), collect(fieldnames(PackageEntry)))], init=h)
230+
Base.:(==)(t1::PackageEntry, t2::PackageEntry) = t1.name == t2.name &&
231+
t1.version == t2.version &&
232+
t1.path == t2.path &&
233+
t1.pinned == t2.pinned &&
234+
t1.repo == t2.repo &&
235+
t1.tree_hash == t2.tree_hash &&
236+
t1.deps == t2.deps # omits `other`
237+
Base.hash(x::PackageEntry, h::UInt) = foldr(hash, [x.name, x.version, x.path, x.pinned, x.repo, x.tree_hash, x.deps], init=h) # omits `other`
232238
const Manifest = Dict{UUID,PackageEntry}
233239

234240
function Base.show(io::IO, pkg::PackageEntry)

0 commit comments

Comments
 (0)