@@ -110,6 +110,7 @@ function finish!(interp::AbstractInterpreter, caller::InferenceState, validation
110
110
elseif isdefined (result, :ci )
111
111
edges = result_edges (interp, caller)
112
112
ci = result. ci
113
+ mi = result. linfo
113
114
# if we aren't cached, we don't need this edge
114
115
# but our caller might, so let's just make it anyways
115
116
if last (result. valid_worlds) >= validation_world
@@ -143,22 +144,27 @@ function finish!(interp::AbstractInterpreter, caller::InferenceState, validation
143
144
resize! (inferred_result. slottypes:: Vector{Any} , nslots)
144
145
resize! (inferred_result. slotnames, nslots)
145
146
end
146
- inferred_result = maybe_compress_codeinfo (interp, result . linfo , inferred_result)
147
+ inferred_result = maybe_compress_codeinfo (interp, mi , inferred_result)
147
148
result. is_src_volatile = false
148
149
elseif ci. owner === nothing
149
150
# The global cache can only handle objects that codegen understands
150
151
inferred_result = nothing
151
152
end
152
153
end
153
154
if debuginfo === nothing
154
- debuginfo = DebugInfo (result . linfo )
155
+ debuginfo = DebugInfo (mi )
155
156
end
157
+ min_world, max_world = first (result. valid_worlds), last (result. valid_worlds)
158
+ ipo_effects = encode_effects (result. ipo_effects)
156
159
time_now = _time_ns ()
157
160
time_self_ns = caller. time_self_ns + (time_now - time_before)
158
161
time_total = (time_now - caller. time_start - caller. time_paused) * 1e-9
159
162
ccall (:jl_update_codeinst , Cvoid, (Any, Any, Int32, UInt, UInt, UInt32, Any, Float64, Float64, Float64, Any, Any),
160
- ci, inferred_result, const_flag, first (result . valid_worlds), last (result . valid_worlds), encode_effects (result . ipo_effects) ,
163
+ ci, inferred_result, const_flag, min_world, max_world, ipo_effects,
161
164
result. analysis_results, time_total, caller. time_caches, time_self_ns * 1e-9 , debuginfo, edges)
165
+ if is_cached (caller) # CACHE_MODE_GLOBAL
166
+ cache_result! (interp, result, ci)
167
+ end
162
168
engine_reject (interp, ci)
163
169
codegen = codegen_cache (interp)
164
170
if ! discard_src && codegen != = nothing && (isa (uncompressed, CodeInfo) || isa (uncompressed, OptimizationState))
@@ -171,7 +177,6 @@ function finish!(interp::AbstractInterpreter, caller::InferenceState, validation
171
177
# This is necessary to get decent bootstrapping performance
172
178
# when compiling the compiler to inject everything eagerly
173
179
# where codegen can start finding and using it right away
174
- mi = result. linfo
175
180
if mi. def isa Method && isa_compileable_sig (mi) && is_cached (caller)
176
181
ccall (:jl_add_codeinst_to_jit , Cvoid, (Any, Any), ci, uncompressed)
177
182
end
@@ -181,6 +186,11 @@ function finish!(interp::AbstractInterpreter, caller::InferenceState, validation
181
186
return nothing
182
187
end
183
188
189
+ function cache_result! (interp:: AbstractInterpreter , result:: InferenceResult , ci:: CodeInstance )
190
+ mi = result. linfo
191
+ code_cache (interp)[mi] = ci
192
+ end
193
+
184
194
function finish! (interp:: AbstractInterpreter , mi:: MethodInstance , ci:: CodeInstance , src:: CodeInfo )
185
195
user_edges = src. edges
186
196
edges = user_edges isa SimpleVector ? user_edges : user_edges === nothing ? Core. svec () : Core. svec (user_edges... )
@@ -215,11 +225,13 @@ function finish!(interp::AbstractInterpreter, mi::MethodInstance, ci::CodeInstan
215
225
end
216
226
217
227
function finish_nocycle (:: AbstractInterpreter , frame:: InferenceState , time_before:: UInt64 )
218
- finishinfer! (frame, frame. interp, frame. cycleid)
228
+ opt_cache = IdDict {MethodInstance,CodeInstance} ()
229
+ finishinfer! (frame, frame. interp, frame. cycleid, opt_cache)
219
230
opt = frame. result. src
220
231
if opt isa OptimizationState # implies `may_optimize(caller.interp) === true`
221
232
optimize (frame. interp, opt, frame. result)
222
233
end
234
+ empty! (opt_cache)
223
235
validation_world = get_world_counter ()
224
236
finish! (frame. interp, frame, validation_world, time_before)
225
237
if isdefined (frame. result, :ci )
@@ -249,10 +261,11 @@ function finish_cycle(::AbstractInterpreter, frames::Vector{AbsIntState}, cyclei
249
261
cycle_valid_worlds = intersect (cycle_valid_worlds, caller. world. valid_worlds)
250
262
cycle_valid_effects = merge_effects (cycle_valid_effects, caller. ipo_effects)
251
263
end
264
+ opt_cache = IdDict {MethodInstance,CodeInstance} ()
252
265
for frameid = cycleid: length (frames)
253
266
caller = frames[frameid]:: InferenceState
254
267
adjust_cycle_frame! (caller, cycle_valid_worlds, cycle_valid_effects)
255
- finishinfer! (caller, caller. interp, cycleid)
268
+ finishinfer! (caller, caller. interp, cycleid, opt_cache )
256
269
time_now = _time_ns ()
257
270
caller. time_self_ns += (time_now - time_before)
258
271
time_before = time_now
@@ -273,6 +286,7 @@ function finish_cycle(::AbstractInterpreter, frames::Vector{AbsIntState}, cyclei
273
286
caller. time_paused = UInt64 (0 )
274
287
caller. time_caches = 0.0
275
288
end
289
+ empty! (opt_cache)
276
290
cycletop = frames[cycleid]:: InferenceState
277
291
time_start = cycletop. time_start
278
292
validation_world = get_world_counter ()
@@ -434,22 +448,6 @@ function maybe_compress_codeinfo(interp::AbstractInterpreter, mi::MethodInstance
434
448
return ci
435
449
end
436
450
437
- function cache_result! (interp:: AbstractInterpreter , result:: InferenceResult , ci:: CodeInstance )
438
- @assert isdefined (ci, :inferred )
439
- # check if the existing linfo metadata is also sufficient to describe the current inference result
440
- # to decide if it is worth caching this right now
441
- mi = result. linfo
442
- cache = WorldView (code_cache (interp), result. valid_worlds)
443
- if haskey (cache, mi)
444
- ci = cache[mi]
445
- # n.b.: accurate edge representation might cause the CodeInstance for this to be constructed later
446
- @assert isdefined (ci, :inferred )
447
- return false
448
- end
449
- code_cache (interp)[mi] = ci
450
- return true
451
- end
452
-
453
451
function cycle_fix_limited (@nospecialize (typ), sv:: InferenceState , cycleid:: Int )
454
452
if typ isa LimitedAccuracy
455
453
frames = sv. callstack:: Vector{AbsIntState}
@@ -579,7 +577,8 @@ const empty_edges = Core.svec()
579
577
580
578
# inference completed on `me`
581
579
# update the MethodInstance
582
- function finishinfer! (me:: InferenceState , interp:: AbstractInterpreter , cycleid:: Int )
580
+ function finishinfer! (me:: InferenceState , interp:: AbstractInterpreter , cycleid:: Int ,
581
+ opt_cache:: IdDict{MethodInstance, CodeInstance} )
583
582
# prepare to run optimization passes on fulltree
584
583
@assert isempty (me. ip)
585
584
# inspect whether our inference had a limited result accuracy,
@@ -635,7 +634,7 @@ function finishinfer!(me::InferenceState, interp::AbstractInterpreter, cycleid::
635
634
# disable optimization if we've already obtained very accurate result
636
635
! result_is_constabi (interp, result)
637
636
if doopt
638
- result. src = OptimizationState (me, interp)
637
+ result. src = OptimizationState (me, interp, opt_cache )
639
638
else
640
639
result. src = me. src # for reflection etc.
641
640
end
@@ -670,23 +669,40 @@ function finishinfer!(me::InferenceState, interp::AbstractInterpreter, cycleid::
670
669
rettype_const = nothing
671
670
const_flags = 0x0
672
671
end
672
+
673
673
di = nothing
674
674
edges = empty_edges # `edges` will be updated within `finish!`
675
675
ci = result. ci
676
+ min_world, max_world = first (result. valid_worlds), last (result. valid_worlds)
676
677
ccall (:jl_fill_codeinst , Cvoid, (Any, Any, Any, Any, Int32, UInt, UInt, UInt32, Any, Any, Any),
677
678
ci, widenconst (result_type), widenconst (result. exc_result), rettype_const, const_flags,
678
- first (result . valid_worlds), last (result . valid_worlds) ,
679
+ min_world, max_world ,
679
680
encode_effects (result. ipo_effects), result. analysis_results, di, edges)
680
681
if is_cached (me) # CACHE_MODE_GLOBAL
681
- cached_result = cache_result! (me. interp, result, ci)
682
- if ! cached_result
682
+ already_cached = is_already_cached (me. interp, result, ci)
683
+ if already_cached
683
684
me. cache_mode = CACHE_MODE_VOLATILE
685
+ else
686
+ opt_cache[result. linfo] = ci
684
687
end
685
688
end
686
689
end
687
690
nothing
688
691
end
689
692
693
+ function is_already_cached (interp:: AbstractInterpreter , result:: InferenceResult , ci:: CodeInstance )
694
+ # check if the existing linfo metadata is also sufficient to describe the current inference result
695
+ # to decide if it is worth caching this right now
696
+ mi = result. linfo
697
+ cache = WorldView (code_cache (interp), result. valid_worlds)
698
+ if haskey (cache, mi)
699
+ # n.b.: accurate edge representation might cause the CodeInstance for this to be constructed later
700
+ @assert isdefined (cache[mi], :inferred )
701
+ return true
702
+ end
703
+ return false
704
+ end
705
+
690
706
# Iterate a series of back-edges that need registering, based on the provided forward edge list.
691
707
# Back-edges are returned as (invokesig, item), where the item is a Binding, MethodInstance, or
692
708
# MethodTable.
0 commit comments