Skip to content

Commit d0f9e26

Browse files
committed
inference: use the same method lookup cache across same inference trial
Previously the method lookup result was created per frame and so the look cache hasn't been use that much. With this change the cache is created per inference, and so the cached result will be used when we already saw the same match in the same inference shot, and it may speed up the lookup time a bit. This commit also setups new `AbstractInterpreter` interface `get_method_lookup_cache` which specifies what method lookup cache is used by each `AbstractInterpreter`. `NativeInterpreter` creates a cache per inference, and so it is valid since lookup is done in the same world age in the same inference shot. External `AbstractInterpreter` doesn't opt into this cache by default, and its behavior won't change in anyway.
1 parent daa0849 commit d0f9e26

File tree

3 files changed

+27
-23
lines changed

3 files changed

+27
-23
lines changed

base/compiler/inferencestate.jl

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -141,7 +141,7 @@ mutable struct InferenceState
141141
cache === :global, false, false,
142142
Effects(consistent, ALWAYS_TRUE, ALWAYS_TRUE, ALWAYS_TRUE,
143143
inbounds_taints_consistency),
144-
CachedMethodTable(method_table(interp)),
144+
CachedMethodTable(get_method_lookup_cache(interp), method_table(interp)),
145145
interp)
146146
result.result = frame
147147
cache !== :no && push!(get_inference_cache(interp), result)

base/compiler/methodtable.jl

Lines changed: 3 additions & 20 deletions
Original file line numberDiff line numberDiff line change
@@ -2,22 +2,6 @@
22

33
abstract type MethodTableView; end
44

5-
struct MethodLookupResult
6-
# Really Vector{Core.MethodMatch}, but it's easier to represent this as
7-
# and work with Vector{Any} on the C side.
8-
matches::Vector{Any}
9-
valid_worlds::WorldRange
10-
ambig::Bool
11-
end
12-
length(result::MethodLookupResult) = length(result.matches)
13-
function iterate(result::MethodLookupResult, args...)
14-
r = iterate(result.matches, args...)
15-
r === nothing && return nothing
16-
match, state = r
17-
return (match::MethodMatch, state)
18-
end
19-
getindex(result::MethodLookupResult, idx::Int) = getindex(result.matches, idx)::MethodMatch
20-
215
"""
226
struct InternalMethodTable <: MethodTableView
237
@@ -46,12 +30,11 @@ Overlays another method table view with an additional local fast path cache that
4630
can respond to repeated, identical queries faster than the original method table.
4731
"""
4832
struct CachedMethodTable{T} <: MethodTableView
49-
cache::IdDict{Any, Union{Missing, MethodLookupResult}}
33+
cache::MethodLookupCache
5034
table::T
35+
CachedMethodTable(cache::MethodLookupCache, table::T) where T = new{T}(cache, table)
36+
CachedMethodTable(::Nothing, table::T) where T = new{T}(MethodLookupCache(), table)
5137
end
52-
CachedMethodTable(table::T) where T =
53-
CachedMethodTable{T}(IdDict{Any, Union{Missing, MethodLookupResult}}(),
54-
table)
5538

5639
"""
5740
findall(sig::Type, view::MethodTableView; limit=typemax(Int))

base/compiler/types.jl

Lines changed: 23 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -111,6 +111,23 @@ decode_effects_override(e::UInt8) =
111111
(e & 0x08) != 0x00,
112112
(e & 0x10) != 0x00)
113113

114+
struct MethodLookupResult
115+
# Really Vector{Core.MethodMatch}, but it's easier to represent this as
116+
# and work with Vector{Any} on the C side.
117+
matches::Vector{Any}
118+
valid_worlds::WorldRange
119+
ambig::Bool
120+
end
121+
length(result::MethodLookupResult) = length(result.matches)
122+
function iterate(result::MethodLookupResult, args...)
123+
r = iterate(result.matches, args...)
124+
r === nothing && return nothing
125+
match, state = r
126+
return (match::MethodMatch, state)
127+
end
128+
getindex(result::MethodLookupResult, idx::Int) = getindex(result.matches, idx)::MethodMatch
129+
const MethodLookupCache = IdDict{Any, Union{Missing, MethodLookupResult}}
130+
114131
"""
115132
InferenceResult
116133
@@ -242,6 +259,8 @@ It contains many parameters used by the compilation pipeline.
242259
struct NativeInterpreter <: AbstractInterpreter
243260
# Cache of inference results for this particular interpreter
244261
cache::Vector{InferenceResult}
262+
# cache of method lookup results
263+
method_lookup_cache::MethodLookupCache
245264
# The world age we're working inside of
246265
world::UInt
247266

@@ -263,10 +282,10 @@ struct NativeInterpreter <: AbstractInterpreter
263282
# incorrect, fail out loudly.
264283
@assert world <= get_world_counter()
265284

266-
267285
return new(
268-
# Initially empty cache
286+
# Initially empty caches
269287
Vector{InferenceResult}(),
288+
MethodLookupCache(),
270289

271290
# world age counter
272291
world,
@@ -316,6 +335,8 @@ may_discard_trees(::AbstractInterpreter) = true
316335
verbose_stmt_info(::AbstractInterpreter) = false
317336

318337
method_table(interp::AbstractInterpreter) = InternalMethodTable(get_world_counter(interp))
338+
get_method_lookup_cache(ni::NativeInterpreter) = ni.method_lookup_cache
339+
get_method_lookup_cache(::AbstractInterpreter) = nothing
319340

320341
"""
321342
By default `AbstractInterpreter` implements the following inference bail out logic:

0 commit comments

Comments
 (0)