Skip to content

Commit 0772f51

Browse files
committed
fix for invalid caching of CodeInfo from typeinf_ext
When inference decided it was not necessary to cache the object, it also skipped all of the work required to make the code valid, which typeinf_ext depends upon. This resulted in caching invalid data, causing effects tests to break unpredictably. This change ensures that we always update the InferenceState with the final result, so that typeinf_ext can get the correct results out of it for internal codegen use. Fixes one of the issues uncovered in #51860
1 parent c54a3f2 commit 0772f51

File tree

6 files changed

+40
-39
lines changed

6 files changed

+40
-39
lines changed

base/compiler/typeinfer.jl

Lines changed: 25 additions & 36 deletions
Original file line numberDiff line numberDiff line change
@@ -218,28 +218,28 @@ function typeinf(interp::NativeInterpreter, frame::InferenceState)
218218
end
219219
typeinf(interp::AbstractInterpreter, frame::InferenceState) = _typeinf(interp, frame)
220220

221-
function finish!(interp::AbstractInterpreter, caller::InferenceResult)
222-
# If we didn't transform the src for caching, we may have to transform
223-
# it anyway for users like typeinf_ext. Do that here.
224-
opt = caller.src
225-
if opt isa OptimizationState{typeof(interp)} # implies `may_optimize(interp) === true`
226-
if opt.ir !== nothing
227-
if caller.must_be_codeinf
228-
caller.src = ir_to_codeinf!(opt)
229-
elseif is_inlineable(opt.src)
230-
# TODO: If the CFG is too big, inlining becomes more expensive and if we're going to
231-
# use this IR over and over, it's worth simplifying it. Round trips through
232-
# CodeInstance do this implicitly, since they recompute the CFG, so try to
233-
# match that behavior here.
234-
# ir = cfg_simplify!(opt.ir)
235-
caller.src = opt.ir
236-
else
237-
# Not cached and not inlineable - drop the ir
238-
caller.src = nothing
239-
end
240-
end
221+
function finish!(interp::AbstractInterpreter, caller::InferenceState)
222+
result = caller.result
223+
valid_worlds = result.valid_worlds
224+
if last(valid_worlds) >= get_world_counter()
225+
# if we aren't cached, we don't need this edge
226+
# but our caller might, so let's just make it anyways
227+
store_backedges(result, caller.stmt_edges[1])
228+
end
229+
opt = result.src
230+
if opt isa OptimizationState && result.must_be_codeinf
231+
result.src = opt = ir_to_codeinf!(opt)
241232
end
242-
return caller.src
233+
if opt isa CodeInfo
234+
opt.min_world = first(valid_worlds)
235+
opt.max_world = last(valid_worlds)
236+
caller.src = opt
237+
else
238+
# In this case caller.src is invalid for clients (such as typeinf_ext) to use
239+
# but that is what !must_be_codeinf permits
240+
# This is hopefully unreachable when must_be_codeinf is true
241+
end
242+
return
243243
end
244244

245245
function _typeinf(interp::AbstractInterpreter, frame::InferenceState)
@@ -266,17 +266,12 @@ function _typeinf(interp::AbstractInterpreter, frame::InferenceState)
266266
end
267267
end
268268
for caller in frames
269-
(; result ) = caller
270-
valid_worlds = result.valid_worlds
271-
if last(valid_worlds) >= get_world_counter()
272-
# if we aren't cached, we don't need this edge
273-
# but our caller might, so let's just make it anyways
274-
store_backedges(result, caller.stmt_edges[1])
275-
end
269+
finish!(caller.interp, caller)
276270
if caller.cached
277-
cache_result!(caller.interp, result)
271+
cache_result!(caller.interp, caller.result)
278272
end
279-
finish!(caller.interp, result)
273+
# n.b. We do not drop result.src here, even though that wastes memory while it is still in the local cache
274+
# since the user might have requested call-site inlining of it.
280275
end
281276
empty!(frames)
282277
return true
@@ -367,13 +362,7 @@ end
367362
function transform_result_for_cache(interp::AbstractInterpreter,
368363
linfo::MethodInstance, valid_worlds::WorldRange, result::InferenceResult)
369364
inferred_result = result.src
370-
if inferred_result isa OptimizationState{typeof(interp)}
371-
# TODO respect must_be_codeinf setting here?
372-
result.src = inferred_result = ir_to_codeinf!(inferred_result)
373-
end
374365
if inferred_result isa CodeInfo
375-
inferred_result.min_world = first(valid_worlds)
376-
inferred_result.max_world = last(valid_worlds)
377366
inferred_result = maybe_compress_codeinfo(interp, linfo, inferred_result)
378367
end
379368
# The global cache can only handle objects that codegen understands

src/aotcompile.cpp

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -246,7 +246,7 @@ static void jl_ci_cache_lookup(const jl_cgparams_t &cgparams, jl_method_instance
246246
else {
247247
*src_out = jl_type_infer(mi, world, 0);
248248
if (*src_out) {
249-
codeinst = jl_get_method_inferred(mi, (*src_out)->rettype, (*src_out)->min_world, (*src_out)->max_world);
249+
codeinst = jl_get_codeinst_for_src(mi, *src_out);
250250
if ((*src_out)->inferred) {
251251
jl_value_t *null = nullptr;
252252
jl_atomic_cmpswap_relaxed(&codeinst->inferred, &null, jl_nothing);

src/gf.c

Lines changed: 10 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -472,6 +472,16 @@ JL_DLLEXPORT jl_code_instance_t *jl_get_method_inferred(
472472
return codeinst;
473473
}
474474

475+
JL_DLLEXPORT jl_code_instance_t *jl_get_codeinst_for_src(
476+
jl_method_instance_t *mi JL_PROPAGATES_ROOT, jl_code_info_t *src)
477+
{
478+
// TODO: copy backedges from src to mi
479+
size_t max_world = src->max_world;
480+
if (max_world >= jl_atomic_load_acquire(&jl_world_counter))
481+
max_world = ~(size_t)0;
482+
return jl_get_method_inferred(mi, src->rettype, src->min_world, max_world);
483+
}
484+
475485
JL_DLLEXPORT jl_code_instance_t *jl_new_codeinst(
476486
jl_method_instance_t *mi, jl_value_t *rettype,
477487
jl_value_t *inferred_const, jl_value_t *inferred,

src/jitlayers.cpp

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -507,6 +507,7 @@ jl_code_instance_t *jl_generate_fptr_impl(jl_method_instance_t *mi JL_PROPAGATES
507507
// see if it is inferred, or try to infer it for ourself.
508508
// (but don't bother with typeinf on macros or toplevel thunks)
509509
src = jl_type_infer(mi, world, 0);
510+
codeinst = nullptr;
510511
}
511512
}
512513
jl_code_instance_t *compiled = jl_method_compiled(mi, world);
@@ -515,7 +516,7 @@ jl_code_instance_t *jl_generate_fptr_impl(jl_method_instance_t *mi JL_PROPAGATES
515516
}
516517
else if (src && jl_is_code_info(src)) {
517518
if (!codeinst) {
518-
codeinst = jl_get_method_inferred(mi, src->rettype, src->min_world, src->max_world);
519+
codeinst = jl_get_codeinst_for_src(mi, src);
519520
if (src->inferred) {
520521
jl_value_t *null = nullptr;
521522
jl_atomic_cmpswap_relaxed(&codeinst->inferred, &null, jl_nothing);

src/jl_exported_funcs.inc

Lines changed: 0 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -226,7 +226,6 @@
226226
XX(jl_get_JIT) \
227227
XX(jl_get_julia_bin) \
228228
XX(jl_get_julia_bindir) \
229-
XX(jl_get_method_inferred) \
230229
XX(jl_get_module_compile) \
231230
XX(jl_get_module_infer) \
232231
XX(jl_get_module_of_binding) \

src/julia_internal.h

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -635,6 +635,8 @@ JL_DLLEXPORT jl_code_instance_t *jl_compile_method_internal(jl_method_instance_t
635635
JL_DLLEXPORT jl_code_instance_t *jl_get_method_inferred(
636636
jl_method_instance_t *mi JL_PROPAGATES_ROOT, jl_value_t *rettype,
637637
size_t min_world, size_t max_world);
638+
JL_DLLEXPORT jl_code_instance_t *jl_get_codeinst_for_src(
639+
jl_method_instance_t *mi JL_PROPAGATES_ROOT, jl_code_info_t *src);
638640
jl_method_instance_t *jl_get_unspecialized_from_mi(jl_method_instance_t *method JL_PROPAGATES_ROOT);
639641
jl_method_instance_t *jl_get_unspecialized(jl_method_t *def JL_PROPAGATES_ROOT);
640642

0 commit comments

Comments
 (0)