• Home
  • Features
  • Pricing
  • Docs
  • Announcements
  • Sign In

JuliaLang / julia / 1652

20 Apr 2026 08:38PM UTC coverage: 77.962% (+0.3%) from 77.623%
1652

push

buildkite

web-flow
codegen: Propagate `ipo_purity_bits` to LLVM function attributes (#61394)

Translate Julia's inferred effects (consistent, effect_free, nothrow,
terminates, notaskstate) into LLVM function attributes so that
middle-end passes like GVN, LICM, and DSE can exploit them.

The key design insight is that GC interactions don't need to be visible
before GC lowering. Call-site declarations get optimistic memory
attributes (e.g. memory(argmem: read)) that enable pre-GC optimizations,
then LateLowerGCFrame widens them to memory(readwrite) before safepoint
analysis so post-GC passes see correct semantics.

Attributes added:
- nounwind: for nothrow functions (with uwtable(async) on definitions
  to preserve .eh_frame for stack scanning)
- mustprogress: for terminating functions
- willreturn: for nothrow+terminating functions
- memory(argmem: read): for consistent+effect_free functions with no
  user-facing pointer arguments (call-site declarations only)
- readnone on gcstack param: for notaskstate functions, so LICM can
  hoist pure calls past heap stores
- "julia.safepoint" marker: on all call-site declarations, used by
  LateLowerGCFrame to identify and widen optimistic attrs

LateLowerGCFrame strips all optimistic attributes (memory effects,
readnone on gcstack) from both call instructions and function
declarations before safepoint analysis runs.

Previously explored in #47844

Developed with Claude

---------

Co-authored-by: Claude <noreply@anthropic.com>
Co-authored-by: Gabriel Baraldi <28694980+gbaraldi@users.noreply.github.com>

65490 of 84002 relevant lines covered (77.96%)

23535049.1 hits per line

Source File
Press 'n' to go to next uncovered line, 'b' for previous

73.58
/Compiler/src/methodtable.jl
1
# This file is a part of Julia. License is MIT: https://julialang.org/license
2

3
struct MethodLookupResult
4
    # Really Vector{Core.MethodMatch}, but it's easier to represent this as
5
    # and work with Vector{Any} on the C side.
6
    matches::Vector{Any}
1,192,993✔
7
    valid_worlds::WorldRange
8
    ambig::Bool
9
end
10
length(result::MethodLookupResult) = length(result.matches)
2,028,383✔
11
function iterate(result::MethodLookupResult, args...)
12
    r = iterate(result.matches, args...)
2,322,993✔
13
    r === nothing && return nothing
2,322,993✔
14
    match, state = r
504,708✔
15
    return (match::MethodMatch, state)
1,790,299✔
16
end
17
getindex(result::MethodLookupResult, idx::Int) = getindex(result.matches, idx)::MethodMatch
1,512,093✔
18

19
abstract type MethodTableView end
20

21
"""
22
    struct InternalMethodTable <: MethodTableView
23

24
A struct representing the state of the internal method table at a
25
particular world age.
26
"""
27
struct InternalMethodTable <: MethodTableView
28
    world::UInt
954,979✔
29
end
30

31
"""
32
    struct OverlayMethodTable <: MethodTableView
33

34
Overlays the internal method table such that specific queries can be redirected to an
35
external table, e.g., to override existing method.
36
"""
37
struct OverlayMethodTable <: MethodTableView
38
    world::UInt
13,560✔
39
    mt::MethodTable
40
end
41

42
struct MethodMatchKey
43
    sig # ::Type
44
    limit::Int
45
    MethodMatchKey(@nospecialize(sig), limit::Int) = new(sig, limit)
96,519✔
46
end
47

48
"""
49
    struct CachedMethodTable <: MethodTableView
50

51
Overlays another method table view with an additional local fast path cache that
52
can respond to repeated, identical queries faster than the original method table.
53
"""
54
struct CachedMethodTable{T<:MethodTableView} <: MethodTableView
55
    cache::IdDict{MethodMatchKey, Union{Nothing,MethodLookupResult}}
2,567✔
56
    table::T
57
end
58
CachedMethodTable(table::T) where T = CachedMethodTable{T}(IdDict{MethodMatchKey, Union{Nothing,MethodLookupResult}}(), table)
2,567✔
59

60
"""
61
    findall(sig::Type, view::MethodTableView; limit::Int=-1) ->
62
        matches::MethodLookupResult or nothing
63

64
Find all methods in the given method table `view` that are applicable to the given signature `sig`.
65
If no applicable methods are found, an empty result is returned.
66
If the number of applicable methods exceeded the specified `limit`, `nothing` is returned.
67
Note that the default setting `limit=-1` does not limit the number of applicable methods.
68
`overlayed` indicates if any of the matching methods comes from an overlayed method table.
69
"""
70
findall(@nospecialize(sig::Type), table::InternalMethodTable; limit::Int=-1) =
2,422,900✔
71
    _findall(sig, nothing, table.world, limit)
72

73
function findall(@nospecialize(sig::Type), table::OverlayMethodTable; limit::Int=-1)
13,470✔
74
    result = _findall(sig, table.mt, table.world, limit)
×
75
    result === nothing && return nothing
×
76
    nr = length(result)
×
77
    if nr ≥ 1 && result[nr].fully_covers
×
78
        # no need to fall back to the internal method table
79
        return result
×
80
    end
81
    # fall back to the internal method table
82
    fallback_result = _findall(sig, nothing, table.world, limit)
×
83
    fallback_result === nothing && return nothing
×
84
    # merge the fallback match results with the internal method table,
85
    # filtering out base methods that are fully covered by overlay methods
86
    overlay_matches = result.matches
×
87
    filtered = filter(fallback_result.matches) do base_match::MethodMatch
×
88
        dominated = any(overlay_matches) do overlay_match::MethodMatch
×
89
            base_match.method.sig <: overlay_match.method.sig
×
90
        end
91
        return !dominated
×
92
    end
93
    return MethodLookupResult(
×
94
        vcat(overlay_matches, filtered),
95
        WorldRange(
96
            max(result.valid_worlds.min_world, fallback_result.valid_worlds.min_world),
97
            min(result.valid_worlds.max_world, fallback_result.valid_worlds.max_world)),
98
        result.ambig | fallback_result.ambig)
99
end
100

101
function _findall(@nospecialize(sig::Type), mt::Union{Nothing,MethodTable}, world::UInt, limit::Int)
102
    _min_val = RefValue{UInt}(typemin(UInt))
1,202,208✔
103
    _max_val = RefValue{UInt}(typemax(UInt))
1,202,208✔
104
    _ambig = RefValue{Int32}(0)
1,202,208✔
105
    ms = _methods_by_ftype(sig, mt, limit, world, false, _min_val, _max_val, _ambig)
1,202,208✔
106
    isa(ms, Vector) || return nothing
1,211,450✔
107
    return MethodLookupResult(ms, WorldRange(_min_val[], _max_val[]), _ambig[] != 0)
1,192,966✔
108
end
109

110
function findall(@nospecialize(sig::Type), table::CachedMethodTable; limit::Int=-1)
1,177,140✔
111
    if isconcretetype(sig)
263,487✔
112
        # as for concrete types, we cache result at on the next level
113
        return findall(sig, table.table; limit)
166,968✔
114
    end
115
    key = MethodMatchKey(sig, limit)
96,519✔
116
    if haskey(table.cache, key)
144,017✔
117
        return table.cache[key]
47,498✔
118
    else
119
        return table.cache[key] = findall(sig, table.table; limit)
49,021✔
120
    end
121
end
122

123
"""
124
    findsup(sig::Type, view::MethodTableView) ->
125
        (match::Union{MethodMatch,Nothing}, valid_worlds::WorldRange, overlayed::Bool)
126

127
Find the (unique) method such that `sig <: match.method.sig`, while being more
128
specific than any other method with the same property. In other words, find the method
129
which is the least upper bound (supremum) under the specificity/subtype relation of
130
the queried `sig`nature. If `sig` is concrete, this is equivalent to asking for the method
131
that will be called given arguments whose types match the given signature.
132
Note that this query is also used to implement `invoke`.
133

134
Such a matching method `match` doesn't necessarily exist.
135
It is possible that no method is an upper bound of `sig`, or
136
it is possible that among the upper bounds, there is no least element.
137
In both cases `nothing` is returned.
138

139
`overlayed` indicates if any of the matching methods comes from an overlayed method table.
140
"""
141
findsup(@nospecialize(sig::Type), table::InternalMethodTable) =
2,347✔
142
    _findsup(sig, nothing, table.world)
143

144
function findsup(@nospecialize(sig::Type), table::OverlayMethodTable)
×
145
    match, valid_worlds = _findsup(sig, table.mt, table.world)
51✔
146
    match !== nothing && return match, valid_worlds
51✔
147
    # fall back to the internal method table
148
    fallback_match, fallback_valid_worlds = _findsup(sig, nothing, table.world)
45✔
149
    return (
45✔
150
        fallback_match,
151
        WorldRange(
152
            max(valid_worlds.min_world, fallback_valid_worlds.min_world),
153
            min(valid_worlds.max_world, fallback_valid_worlds.max_world)))
154
end
155

156
function _findsup(@nospecialize(sig::Type), mt::Union{Nothing,MethodTable}, world::UInt)
169✔
157
    min_valid = RefValue{UInt}(typemin(UInt))
2,681✔
158
    max_valid = RefValue{UInt}(typemax(UInt))
2,681✔
159
    match = ccall(:jl_gf_invoke_lookup_worlds, Any, (Any, Any, UInt, Ptr{Csize_t}, Ptr{Csize_t}),
2,681✔
160
                   sig, mt, world, min_valid, max_valid)::Union{MethodMatch, Nothing}
161
    valid_worlds = WorldRange(min_valid[], max_valid[])
2,681✔
162
    return match, valid_worlds
2,218✔
163
end
164

165
# This query is not cached
166
findsup(@nospecialize(sig::Type), table::CachedMethodTable) = findsup(sig, table.table)
25✔
STATUS · Troubleshooting · Open an Issue · Sales · Support · CAREERS · ENTERPRISE · START FREE · SCHEDULE DEMO
ANNOUNCEMENTS · TWITTER · TOS & SLA · Supported CI Services · What's a CI service? · Automated Testing

© 2026 Coveralls, Inc