Skip to content

Commit 5934b45

Browse files
vtjnashtecosaur
authored andcommitted
undo breaking change of removing parent field from CodeInfo (JuliaLang#53393)
This drops the unnecessary breaking change from JuliaLang#53219 by re-adding the optional `parent` field to CodeInfo. A few months ago, I had actually already put together a branch that also fixed Keno's complaints about how it was not set reliably, so I copied that code here also, so that it should get set more reliably whenever a CodeInfo is associated with a MethodInstance (either because it called `retrieve_code_info` to get IR from the Method or `uncompress_ir` to get it from the inference cache). This does not entirely fix Cthulhu's test errors, since I don't see any particular reason to re-introduce the other fields (min_world, max_world, inferred, edges, method_for_inference_limit_heuristics) that got removed or are now set incorrectly, and most errors appear to be instead related to the `Expr(:boundscheck, true/false)` change. However, they could be trivially re-added back as placeholders, if someone encounters a broken package that still needs them.
2 parents a3636cb + ff405e2 commit 5934b45

21 files changed

+136
-96
lines changed

base/compiler/abstractinterpretation.jl

+1-1
Original file line numberDiff line numberDiff line change
@@ -1181,7 +1181,7 @@ function const_prop_methodinstance_heuristic(interp::AbstractInterpreter,
11811181
if isa(code, CodeInstance)
11821182
inferred = @atomic :monotonic code.inferred
11831183
# TODO propagate a specific `CallInfo` that conveys information about this call
1184-
if inlining_policy(interp, inferred, NoCallInfo(), IR_FLAG_NULL) !== nothing
1184+
if src_inlining_policy(interp, inferred, NoCallInfo(), IR_FLAG_NULL)
11851185
return true
11861186
end
11871187
end

base/compiler/inferencestate.jl

+1-1
Original file line numberDiff line numberDiff line change
@@ -800,7 +800,7 @@ function IRInterpretationState(interp::AbstractInterpreter,
800800
@assert code.def === mi
801801
src = @atomic :monotonic code.inferred
802802
if isa(src, String)
803-
src = _uncompressed_ir(mi.def, src)
803+
src = _uncompressed_ir(code, src)
804804
else
805805
isa(src, CodeInfo) || return nothing
806806
end

base/compiler/optimize.jl

+9-7
Original file line numberDiff line numberDiff line change
@@ -107,21 +107,23 @@ is_declared_noinline(@nospecialize src::MaybeCompressed) =
107107
# OptimizationState #
108108
#####################
109109

110-
function inlining_policy(interp::AbstractInterpreter,
110+
# return whether this src should be inlined. If so, retrieve_ir_for_inlining must return an IRCode from it
111+
function src_inlining_policy(interp::AbstractInterpreter,
111112
@nospecialize(src), @nospecialize(info::CallInfo), stmt_flag::UInt32)
112113
if isa(src, MaybeCompressed)
113114
src_inlineable = is_stmt_inline(stmt_flag) || is_inlineable(src)
114-
return src_inlineable ? src : nothing
115+
return src_inlineable
115116
elseif isa(src, IRCode)
116-
return src
117+
return true
117118
elseif isa(src, SemiConcreteResult)
118-
return src
119-
elseif isa(src, CodeInstance)
120-
return inlining_policy(interp, src.inferred, info, stmt_flag)
119+
return true
121120
end
122-
return nothing
121+
@assert !isa(src, CodeInstance) # handled by caller
122+
return false
123123
end
124124

125+
function inlining_policy end # deprecated legacy name used by Cthulhu
126+
125127
struct InliningState{Interp<:AbstractInterpreter}
126128
edges::Vector{Any}
127129
world::UInt

base/compiler/ssair/inlining.jl

+40-25
Original file line numberDiff line numberDiff line change
@@ -838,7 +838,7 @@ function compileable_specialization(match::MethodMatch, effects::Effects,
838838
end
839839

840840
struct InferredResult
841-
src::Any
841+
src::Any # CodeInfo or IRCode
842842
effects::Effects
843843
InferredResult(@nospecialize(src), effects::Effects) = new(src, effects)
844844
end
@@ -849,11 +849,9 @@ end
849849
# in this case function can be inlined to a constant
850850
return ConstantCase(quoted(code.rettype_const))
851851
end
852-
src = @atomic :monotonic code.inferred
853-
effects = decode_effects(code.ipo_purity_bits)
854-
return InferredResult(src, effects)
852+
return code
855853
end
856-
return InferredResult(nothing, Effects())
854+
return nothing
857855
end
858856
@inline function get_local_result(inf_result::InferenceResult)
859857
effects = inf_result.ipo_effects
@@ -887,7 +885,15 @@ function resolve_todo(mi::MethodInstance, result::Union{Nothing,InferenceResult,
887885
add_inlining_backedge!(et, mi)
888886
return inferred_result
889887
end
890-
(; src, effects) = inferred_result
888+
if inferred_result isa InferredResult
889+
(; src, effects) = inferred_result
890+
elseif inferred_result isa CodeInstance
891+
src = @atomic :monotonic inferred_result.inferred
892+
effects = decode_effects(inferred_result.ipo_purity_bits)
893+
else
894+
src = nothing
895+
effects = Effects()
896+
end
891897

892898
# the duplicated check might have been done already within `analyze_method!`, but still
893899
# we need it here too since we may come here directly using a constant-prop' result
@@ -896,12 +902,13 @@ function resolve_todo(mi::MethodInstance, result::Union{Nothing,InferenceResult,
896902
compilesig_invokes=OptimizationParams(state.interp).compilesig_invokes)
897903
end
898904

899-
src = inlining_policy(state.interp, src, info, flag)
900-
src === nothing && return compileable_specialization(mi, effects, et, info;
901-
compilesig_invokes=OptimizationParams(state.interp).compilesig_invokes)
905+
src_inlining_policy(state.interp, src, info, flag) ||
906+
return compileable_specialization(mi, effects, et, info;
907+
compilesig_invokes=OptimizationParams(state.interp).compilesig_invokes)
902908

903909
add_inlining_backedge!(et, mi)
904-
ir = retrieve_ir_for_inlining(mi, src, preserve_local_sources)
910+
ir = inferred_result isa CodeInstance ? retrieve_ir_for_inlining(inferred_result, src) :
911+
retrieve_ir_for_inlining(mi, src, preserve_local_sources)
905912
return InliningTodo(mi, ir, effects)
906913
end
907914

@@ -919,14 +926,22 @@ function resolve_todo(mi::MethodInstance, @nospecialize(info::CallInfo), flag::U
919926
add_inlining_backedge!(et, mi)
920927
return cached_result
921928
end
922-
(; src, effects) = cached_result
923-
924-
src = inlining_policy(state.interp, src, info, flag)
925-
926-
src === nothing && return nothing
929+
if cached_result isa InferredResult
930+
(; src, effects) = cached_result
931+
elseif cached_result isa CodeInstance
932+
src = @atomic :monotonic cached_result.inferred
933+
effects = decode_effects(cached_result.ipo_purity_bits)
934+
else
935+
src = nothing
936+
effects = Effects()
937+
end
927938

939+
preserve_local_sources = true
940+
src_inlining_policy(state.interp, src, info, flag) || return nothing
941+
ir = cached_result isa CodeInstance ? retrieve_ir_for_inlining(cached_result, src) :
942+
retrieve_ir_for_inlining(mi, src, preserve_local_sources)
928943
add_inlining_backedge!(et, mi)
929-
return InliningTodo(mi, retrieve_ir_for_inlining(mi, src), effects)
944+
return InliningTodo(mi, ir, effects)
930945
end
931946

932947
function validate_sparams(sparams::SimpleVector)
@@ -979,17 +994,17 @@ function analyze_method!(match::MethodMatch, argtypes::Vector{Any},
979994
return resolve_todo(mi, volatile_inf_result, info, flag, state; invokesig)
980995
end
981996

982-
function retrieve_ir_for_inlining(mi::MethodInstance, src::String, ::Bool=true)
983-
src = _uncompressed_ir(mi.def, src)
984-
return inflate_ir!(src, mi)
997+
function retrieve_ir_for_inlining(cached_result::CodeInstance, src::MaybeCompressed)
998+
src = _uncompressed_ir(cached_result, src)::CodeInfo
999+
return inflate_ir!(src, cached_result.def)
9851000
end
986-
function retrieve_ir_for_inlining(mi::MethodInstance, src::CodeInfo, preserve_local_sources::Bool=true)
1001+
function retrieve_ir_for_inlining(mi::MethodInstance, src::CodeInfo, preserve_local_sources::Bool)
9871002
if preserve_local_sources
9881003
src = copy(src)
9891004
end
9901005
return inflate_ir!(src, mi)
9911006
end
992-
function retrieve_ir_for_inlining(::MethodInstance, ir::IRCode, preserve_local_sources::Bool=true)
1007+
function retrieve_ir_for_inlining(mi::MethodInstance, ir::IRCode, preserve_local_sources::Bool)
9931008
if preserve_local_sources
9941009
ir = copy(ir)
9951010
end
@@ -1494,13 +1509,13 @@ function semiconcrete_result_item(result::SemiConcreteResult,
14941509
return compileable_specialization(mi, result.effects, et, info;
14951510
compilesig_invokes=OptimizationParams(state.interp).compilesig_invokes)
14961511
end
1497-
ir = inlining_policy(state.interp, result.ir, info, flag)
1498-
ir === nothing && return compileable_specialization(mi, result.effects, et, info;
1499-
compilesig_invokes=OptimizationParams(state.interp).compilesig_invokes)
1512+
src_inlining_policy(state.interp, result.ir, info, flag) ||
1513+
return compileable_specialization(mi, result.effects, et, info;
1514+
compilesig_invokes=OptimizationParams(state.interp).compilesig_invokes)
15001515

15011516
add_inlining_backedge!(et, mi)
15021517
preserve_local_sources = OptimizationParams(state.interp).preserve_local_sources
1503-
ir = retrieve_ir_for_inlining(mi, ir, preserve_local_sources)
1518+
ir = retrieve_ir_for_inlining(mi, result.ir, preserve_local_sources)
15041519
return InliningTodo(mi, ir, result.effects)
15051520
end
15061521

base/compiler/ssair/legacy.jl

+2
Original file line numberDiff line numberDiff line change
@@ -55,6 +55,8 @@ Mainly used for testing or interactive use.
5555
inflate_ir(ci::CodeInfo, linfo::MethodInstance) = inflate_ir!(copy(ci), linfo)
5656
inflate_ir(ci::CodeInfo, sptypes::Vector{VarState}, argtypes::Vector{Any}) = inflate_ir!(copy(ci), sptypes, argtypes)
5757
function inflate_ir(ci::CodeInfo)
58+
parent = ci.parent
59+
isa(parent, MethodInstance) && return inflate_ir(ci, parent)
5860
# XXX the length of `ci.slotflags` may be different from the actual number of call
5961
# arguments, but we really don't know that information in this case
6062
argtypes = Any[ Any for i = 1:length(ci.slotflags) ]

base/compiler/ssair/passes.jl

+3-4
Original file line numberDiff line numberDiff line change
@@ -1492,12 +1492,11 @@ function try_inline_finalizer!(ir::IRCode, argexprs::Vector{Any}, idx::Int,
14921492
end
14931493
src = @atomic :monotonic code.inferred
14941494
else
1495-
src = nothing
1495+
return false
14961496
end
14971497

1498-
src = inlining_policy(inlining.interp, src, info, IR_FLAG_NULL)
1499-
src === nothing && return false
1500-
src = retrieve_ir_for_inlining(mi, src)
1498+
src_inlining_policy(inlining.interp, src, info, IR_FLAG_NULL) || return false
1499+
src = retrieve_ir_for_inlining(code, src)
15011500

15021501
# For now: Require finalizer to only have one basic block
15031502
length(src.cfg.blocks) == 1 || return false

base/compiler/typeinfer.jl

+21-19
Original file line numberDiff line numberDiff line change
@@ -310,11 +310,20 @@ function CodeInstance(interp::AbstractInterpreter, result::InferenceResult;
310310
end
311311
end
312312
relocatability = 0x0
313+
owner = cache_owner(interp)
313314
if const_flags == 0x3 && can_discard_trees
314315
inferred_result = nothing
315316
relocatability = 0x1
316317
else
317318
inferred_result = transform_result_for_cache(interp, result.linfo, result.valid_worlds, result, can_discard_trees)
319+
if inferred_result isa CodeInfo
320+
uncompressed = inferred_result
321+
inferred_result = maybe_compress_codeinfo(interp, result.linfo, inferred_result, can_discard_trees)
322+
result.is_src_volatile |= uncompressed !== inferred_result
323+
elseif owner === nothing
324+
# The global cache can only handle objects that codegen understands
325+
inferred_result = nothing
326+
end
318327
if isa(inferred_result, String)
319328
t = @_gc_preserve_begin inferred_result
320329
relocatability = unsafe_load(unsafe_convert(Ptr{UInt8}, inferred_result), Core.sizeof(inferred_result))
@@ -323,15 +332,21 @@ function CodeInstance(interp::AbstractInterpreter, result::InferenceResult;
323332
relocatability = 0x1
324333
end
325334
end
326-
# relocatability = isa(inferred_result, String) ? inferred_result[end] : UInt8(0)
327-
return CodeInstance(result.linfo, cache_owner(interp),
335+
# n.b. relocatability = (isa(inferred_result, String) && inferred_result[end]) || inferred_result === nothing
336+
return CodeInstance(result.linfo, owner,
328337
widenconst(result_type), widenconst(result.exc_result), rettype_const, inferred_result,
329338
const_flags, first(result.valid_worlds), last(result.valid_worlds),
330339
# TODO: Actually do something with non-IPO effects
331340
encode_effects(result.ipo_effects), encode_effects(result.ipo_effects), result.analysis_results,
332341
relocatability)
333342
end
334343

344+
function transform_result_for_cache(interp::AbstractInterpreter,
345+
linfo::MethodInstance, valid_worlds::WorldRange, result::InferenceResult,
346+
can_discard_trees::Bool=may_discard_trees(interp))
347+
return result.src
348+
end
349+
335350
function maybe_compress_codeinfo(interp::AbstractInterpreter, linfo::MethodInstance, ci::CodeInfo,
336351
can_discard_trees::Bool=may_discard_trees(interp))
337352
def = linfo.def
@@ -354,22 +369,6 @@ function maybe_compress_codeinfo(interp::AbstractInterpreter, linfo::MethodInsta
354369
end
355370
end
356371

357-
function transform_result_for_cache(interp::AbstractInterpreter,
358-
linfo::MethodInstance, valid_worlds::WorldRange, result::InferenceResult,
359-
can_discard_trees::Bool=may_discard_trees(interp))
360-
inferred_result = result.src
361-
if inferred_result isa CodeInfo
362-
uncompressed = inferred_result
363-
inferred_result = maybe_compress_codeinfo(interp, linfo, inferred_result, can_discard_trees)
364-
result.is_src_volatile |= uncompressed !== inferred_result
365-
end
366-
# The global cache can only handle objects that codegen understands
367-
if !isa(inferred_result, MaybeCompressed)
368-
inferred_result = nothing
369-
end
370-
return inferred_result
371-
end
372-
373372
function cache_result!(interp::AbstractInterpreter, result::InferenceResult)
374373
if last(result.valid_worlds) == get_world_counter()
375374
# if we've successfully recorded all of the backedges in the global reverse-cache,
@@ -874,7 +873,7 @@ function typeinf_edge(interp::AbstractInterpreter, method::Method, @nospecialize
874873
exc_bestguess = refine_exception_type(frame.exc_bestguess, effects)
875874
# propagate newly inferred source to the inliner, allowing efficient inlining w/o deserialization:
876875
# note that this result is cached globally exclusively, we can use this local result destructively
877-
volatile_inf_result = isinferred && (force_inline || inlining_policy(interp, result.src, NoCallInfo(), IR_FLAG_NULL) !== nothing) ?
876+
volatile_inf_result = isinferred && (force_inline || src_inlining_policy(interp, result.src, NoCallInfo(), IR_FLAG_NULL) !== nothing) ?
878877
VolatileInferenceResult(result) : nothing
879878
return EdgeCallResult(frame.bestguess, exc_bestguess, edge, effects, volatile_inf_result)
880879
elseif frame === true
@@ -930,6 +929,7 @@ function codeinfo_for_const(interp::AbstractInterpreter, mi::MethodInstance, @no
930929
tree.linetable = LineInfoNode[LineInfoNode(method.module, method.name, method.file, method.line, Int32(0))]
931930
tree.ssaflags = UInt32[0]
932931
set_inlineable!(tree, true)
932+
tree.parent = mi
933933
return tree
934934
end
935935

@@ -1091,6 +1091,8 @@ function ci_meets_requirement(code::CodeInstance, source_mode::UInt8, ci_is_cach
10911091
return false
10921092
end
10931093

1094+
_uncompressed_ir(ci::Core.CodeInstance, s::String) = ccall(:jl_uncompress_ir, Any, (Any, Any, Any), ci.def.def::Method, ci, s)::CodeInfo
1095+
10941096
# compute (and cache) an inferred AST and return type
10951097
function typeinf_ext(interp::AbstractInterpreter, mi::MethodInstance, source_mode::UInt8)
10961098
start_time = ccall(:jl_typeinf_timing_begin, UInt64, ())

base/compiler/utilities.jl

+2-1
Original file line numberDiff line numberDiff line change
@@ -143,12 +143,13 @@ function retrieve_code_info(linfo::MethodInstance, world::UInt)
143143
# can happen in images built with --strip-ir
144144
return nothing
145145
elseif isa(src, String)
146-
c = _uncompressed_ir(def, src)
146+
c = ccall(:jl_uncompress_ir, Any, (Any, Ptr{Cvoid}, Any), def, C_NULL, src)
147147
else
148148
c = copy(src::CodeInfo)
149149
end
150150
end
151151
if c isa CodeInfo
152+
c.parent = linfo
152153
return c
153154
end
154155
return nothing

base/reflection.jl

+7-5
Original file line numberDiff line numberDiff line change
@@ -1313,12 +1313,14 @@ function length(mt::Core.MethodTable)
13131313
end
13141314
isempty(mt::Core.MethodTable) = (mt.defs === nothing)
13151315

1316-
uncompressed_ir(m::Method) = isdefined(m, :source) ? _uncompressed_ir(m, m.source) :
1316+
uncompressed_ir(m::Method) = isdefined(m, :source) ? _uncompressed_ir(m) :
13171317
isdefined(m, :generator) ? error("Method is @generated; try `code_lowered` instead.") :
13181318
error("Code for this Method is not available.")
1319-
_uncompressed_ir(m::Method, s::CodeInfo) = copy(s)
1320-
_uncompressed_ir(m::Method, s::String) = ccall(:jl_uncompress_ir, Any, (Any, Any), m, s)::CodeInfo
1321-
_uncompressed_ir(ci::Core.CodeInstance, s::String) = ccall(:jl_uncompress_ir, Any, (Any, Any), ci.def.def::Method, s)::CodeInfo
1319+
function _uncompressed_ir(m::Method)
1320+
s = m.source
1321+
s isa String && (s = ccall(:jl_uncompress_ir, Any, (Any, Ptr{Cvoid}, Any), m, C_NULL, s))
1322+
return s::CodeInfo
1323+
end
13221324
# for backwards compat
13231325
const uncompressed_ast = uncompressed_ir
13241326
const _uncompressed_ast = _uncompressed_ir
@@ -1632,7 +1634,7 @@ function get_oc_code_rt(@nospecialize(oc::Core.OpaqueClosure))
16321634
ccall(:jl_is_in_pure_context, Bool, ()) && error("code reflection cannot be used from generated functions")
16331635
m = oc.source
16341636
if isa(m, Method)
1635-
code = _uncompressed_ir(m, m.source)
1637+
code = _uncompressed_ir(m)
16361638
return Pair{CodeInfo,Any}(code, typeof(oc).parameters[2])
16371639
else
16381640
error("encountered invalid Core.OpaqueClosure object")

src/aotcompile.cpp

+3-3
Original file line numberDiff line numberDiff line change
@@ -301,7 +301,7 @@ static void jl_ci_cache_lookup(const jl_cgparams_t &cgparams, jl_method_instance
301301
if ((jl_value_t*)*src_out == jl_nothing)
302302
*src_out = NULL;
303303
if (*src_out && jl_is_method(def))
304-
*src_out = jl_uncompress_ir(def, (jl_value_t*)*src_out);
304+
*src_out = jl_uncompress_ir(def, codeinst, (jl_value_t*)*src_out);
305305
}
306306
if (*src_out == NULL || !jl_is_code_info(*src_out)) {
307307
if (cgparams.lookup != jl_rettype_inferred_addr) {
@@ -1950,7 +1950,7 @@ extern "C" JL_DLLEXPORT_CODEGEN jl_code_info_t *jl_gdbdumpcode(jl_method_instanc
19501950
src = (jl_code_info_t*)jl_atomic_load_relaxed(&codeinst->inferred);
19511951
if ((jl_value_t*)src != jl_nothing && !jl_is_code_info(src) && jl_is_method(mi->def.method)) {
19521952
JL_GC_PUSH2(&codeinst, &src);
1953-
src = jl_uncompress_ir(mi->def.method, (jl_value_t*)src);
1953+
src = jl_uncompress_ir(mi->def.method, codeinst, (jl_value_t*)src);
19541954
JL_GC_POP();
19551955
}
19561956
}
@@ -1989,7 +1989,7 @@ void jl_get_llvmf_defn_impl(jl_llvmf_dump_t* dump, jl_method_instance_t *mi, siz
19891989
}
19901990
if (src) {
19911991
if ((jl_value_t*)src != jl_nothing && !jl_is_code_info(src) && jl_is_method(mi->def.method))
1992-
src = jl_uncompress_ir(mi->def.method, (jl_value_t*)src);
1992+
src = jl_uncompress_ir(mi->def.method, codeinst, (jl_value_t*)src);
19931993
}
19941994

19951995
// emit this function into a new llvm module

src/codegen.cpp

+2-2
Original file line numberDiff line numberDiff line change
@@ -6015,7 +6015,7 @@ static std::pair<Function*, Function*> get_oc_function(jl_codectx_t &ctx, jl_met
60156015

60166016
if (it == ctx.emission_context.compiled_functions.end()) {
60176017
++EmittedOpaqueClosureFunctions;
6018-
jl_code_info_t *ir = jl_uncompress_ir(closure_method, (jl_value_t*)inferred);
6018+
jl_code_info_t *ir = jl_uncompress_ir(closure_method, ci, (jl_value_t*)inferred);
60196019
JL_GC_PUSH1(&ir);
60206020
// TODO: Emit this inline and outline it late using LLVM's coroutine support.
60216021
orc::ThreadSafeModule closure_m = jl_create_ts_module(
@@ -9570,7 +9570,7 @@ jl_llvm_functions_t jl_emit_codeinst(
95709570
return jl_emit_oc_wrapper(m, params, codeinst->def, codeinst->rettype);
95719571
}
95729572
if (src && (jl_value_t*)src != jl_nothing && jl_is_method(def))
9573-
src = jl_uncompress_ir(def, (jl_value_t*)src);
9573+
src = jl_uncompress_ir(def, codeinst, (jl_value_t*)src);
95749574
if (!src || !jl_is_code_info(src)) {
95759575
JL_GC_POP();
95769576
m = orc::ThreadSafeModule();

0 commit comments

Comments
 (0)