Skip to content

Commit f345ee7

Browse files
authored
compiler: consolidate staticdata.jl and invalidations.jl into Compiler proper [NFCI] (#59238)
This aims to consolidate more of the code that is expected to run in typeinf_world into Compiler proper. The intent is that these are likely to gain more interaction (both directions) with inference, as the compiler should use this mini-compiler and vice versa. We actually might want a `Base.CompilerUtils` module so that the `Compiler` package itself is smaller and less reliant on internal APIs, but for now just move these into a submodule of Compiler. Written by Claude
1 parent 303b5d8 commit f345ee7

File tree

10 files changed

+71
-68
lines changed

10 files changed

+71
-68
lines changed

Compiler/src/Compiler.jl

Lines changed: 10 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -48,8 +48,8 @@ using Base: @_foldable_meta, @_gc_preserve_begin, @_gc_preserve_end, @nospeciali
4848
PARTITION_KIND_GLOBAL, PARTITION_KIND_UNDEF_CONST, PARTITION_KIND_BACKDATED_CONST, PARTITION_KIND_DECLARED,
4949
PARTITION_FLAG_DEPWARN,
5050
Base, BitVector, Bottom, Callable, DataTypeFieldDesc,
51-
EffectsOverride, Filter, Generator, IteratorSize, JLOptions, NUM_EFFECTS_OVERRIDES,
52-
OneTo, Ordering, RefValue, SizeUnknown, _NAMEDTUPLE_NAME,
51+
EffectsOverride, Filter, Generator, NUM_EFFECTS_OVERRIDES,
52+
OneTo, Ordering, RefValue, _NAMEDTUPLE_NAME,
5353
_array_for, _bits_findnext, _methods_by_ftype, _uniontypes, all, allocatedinline, any,
5454
argument_datatype, binding_kind, cconvert, copy_exprargs, datatype_arrayelem,
5555
datatype_fieldcount, datatype_fieldtypes, datatype_layoutsize, datatype_nfields,
@@ -64,9 +64,11 @@ using Base: @_foldable_meta, @_gc_preserve_begin, @_gc_preserve_end, @nospeciali
6464
partition_restriction, quoted, rename_unionall, rewrap_unionall, specialize_method,
6565
structdiff, tls_world_age, unconstrain_vararg_length, unionlen, uniontype_layout,
6666
uniontypes, unsafe_convert, unwrap_unionall, unwrapva, vect, widen_diagonal,
67-
_uncompressed_ir, maybe_add_binding_backedge!, datatype_min_ninitialized,
67+
_uncompressed_ir, datatype_min_ninitialized,
6868
partialstruct_init_undefs, fieldcount_noerror, _eval_import, _eval_using,
69-
get_ci_mi
69+
get_ci_mi, get_methodtable, morespecific, specializations, has_image_globalref,
70+
PARTITION_MASK_KIND, PARTITION_KIND_GUARD, PARTITION_FLAG_EXPORTED, PARTITION_FLAG_DEPRECATED,
71+
BINDING_FLAG_ANY_IMPLICIT_EDGES, is_some_implicit, IteratorSize, SizeUnknown, get_require_world, JLOptions
7072

7173
using Base.Order
7274

@@ -188,6 +190,10 @@ include("bootstrap.jl")
188190
include("reflection_interface.jl")
189191
include("opaque_closure.jl")
190192

193+
baremodule ReinferUtils end
194+
include(ReinferUtils, "reinfer.jl")
195+
include(ReinferUtils, "bindinginvalidations.jl")
196+
191197
macro __SOURCE_FILE__()
192198
__source__.file === nothing && return nothing
193199
return QuoteNode(__source__.file::Symbol)

base/invalidation.jl renamed to Compiler/src/bindinginvalidations.jl

Lines changed: 13 additions & 28 deletions
Original file line numberDiff line numberDiff line change
@@ -1,26 +1,17 @@
11
# This file is a part of Julia. License is MIT: https://julialang.org/license
22

3-
struct GlobalRefIterator
4-
mod::Module
5-
end
6-
IteratorSize(::Type{GlobalRefIterator}) = SizeUnknown()
7-
globalrefs(mod::Module) = GlobalRefIterator(mod)
8-
9-
function iterate(gri::GlobalRefIterator, i = 1)
10-
m = gri.mod
11-
table = ccall(:jl_module_get_bindings, Ref{SimpleVector}, (Any,), m)
12-
i > length(table) && return nothing
13-
b = table[i]
14-
b === nothing && return iterate(gri, i+1)
15-
return ((b::Core.Binding).globalref, i+1)
16-
end
3+
using ..Compiler: _uncompressed_ir, specializations, get_ci_mi, convert, unsafe_load, cglobal, generating_output, has_image_globalref,
4+
PARTITION_MASK_KIND, PARTITION_KIND_GUARD, PARTITION_FLAG_EXPORTED, PARTITION_FLAG_DEPRECATED,
5+
BINDING_FLAG_ANY_IMPLICIT_EDGES, binding_kind, partition_restriction, is_some_imported,
6+
is_some_binding_imported, is_some_implicit, SizeUnknown, maybe_add_binding_backedge!, walk_binding_partition, abstract_eval_partition_load, userefs
7+
using .Core: SimpleVector, CodeInfo
178

189
function foreachgr(visit, src::CodeInfo)
1910
stmts = src.code
2011
for i = 1:length(stmts)
2112
stmt = stmts[i]
2213
isa(stmt, GlobalRef) && visit(stmt)
23-
for ur in Compiler.userefs(stmt)
14+
for ur in userefs(stmt)
2415
arg = ur[]
2516
isa(arg, GlobalRef) && visit(arg)
2617
end
@@ -35,7 +26,7 @@ function anygr(visit, src::CodeInfo)
3526
visit(stmt) && return true
3627
continue
3728
end
38-
for ur in Compiler.userefs(stmt)
29+
for ur in userefs(stmt)
3930
arg = ur[]
4031
isa(arg, GlobalRef) && visit(arg) && return true
4132
end
@@ -69,7 +60,7 @@ function invalidate_method_for_globalref!(gr::GlobalRef, method::Method, invalid
6960
src = _uncompressed_ir(method)
7061
invalidate_all = should_invalidate_code_for_globalref(gr, src)
7162
end
72-
if invalidate_all && !Base.generating_output()
63+
if invalidate_all && !generating_output()
7364
@atomic method.did_scan_source |= 0x4
7465
end
7566
invalidated_any = false
@@ -99,15 +90,15 @@ export_affecting_partition_flags(bpart::Core.BindingPartition) =
9990
function invalidate_code_for_globalref!(b::Core.Binding, invalidated_bpart::Core.BindingPartition, new_bpart::Core.BindingPartition, new_max_world::UInt)
10091
gr = b.globalref
10192

102-
(_, (ib, ibpart)) = Compiler.walk_binding_partition(b, invalidated_bpart, new_max_world)
103-
(_, (nb, nbpart)) = Compiler.walk_binding_partition(b, new_bpart, new_max_world+1)
93+
(_, (ib, ibpart)) = walk_binding_partition(b, invalidated_bpart, new_max_world)
94+
(_, (nb, nbpart)) = walk_binding_partition(b, new_bpart, new_max_world+1)
10495

10596
# `abstract_eval_partition_load` is the maximum amount of information that inference
10697
# reads from a binding partition. If this information does not change - we do not need to
10798
# invalidate any code that inference created, because we know that the result will not change.
10899
need_to_invalidate_code =
109-
Compiler.abstract_eval_partition_load(nothing, ib, ibpart) !==
110-
Compiler.abstract_eval_partition_load(nothing, nb, nbpart)
100+
abstract_eval_partition_load(nothing, ib, ibpart) !==
101+
abstract_eval_partition_load(nothing, nb, nbpart)
111102

112103
need_to_invalidate_export = export_affecting_partition_flags(invalidated_bpart) !==
113104
export_affecting_partition_flags(new_bpart)
@@ -173,12 +164,6 @@ end
173164
invalidate_code_for_globalref!(gr::GlobalRef, invalidated_bpart::Core.BindingPartition, new_bpart::Core.BindingPartition, new_max_world::UInt) =
174165
invalidate_code_for_globalref!(convert(Core.Binding, gr), invalidated_bpart, new_bpart, new_max_world)
175166

176-
function maybe_add_binding_backedge!(b::Core.Binding, edge::Union{Method, CodeInstance})
177-
meth = isa(edge, Method) ? edge : get_ci_mi(edge).def
178-
ccall(:jl_maybe_add_binding_backedge, Cint, (Any, Any, Any), b, edge, meth)
179-
return nothing
180-
end
181-
182167
function binding_was_invalidated(b::Core.Binding)
183168
# At least one partition is required for invalidation
184169
!isdefined(b, :partitions) && return false
@@ -206,7 +191,7 @@ function scan_new_method!(method::Method, image_backedges_only::Bool)
206191
end
207192

208193
function scan_new_methods!(extext_methods::Vector{Any}, internal_methods::Vector{Any}, image_backedges_only::Bool)
209-
if image_backedges_only && Base.generating_output(true)
194+
if image_backedges_only && generating_output(true)
210195
# Replacing image bindings is forbidden during incremental precompilation - skip backedge insertion
211196
return
212197
end

base/staticdata.jl renamed to Compiler/src/reinfer.jl

Lines changed: 27 additions & 18 deletions
Original file line numberDiff line numberDiff line change
@@ -1,10 +1,13 @@
11
# This file is a part of Julia. License is MIT: https://julialang.org/license
22

3+
using ..Compiler.Base
4+
using ..Compiler: _findsup, store_backedges, JLOptions, get_world_counter,
5+
_methods_by_ftype, get_methodtable, get_ci_mi, should_instrument,
6+
morespecific, RefValue, get_require_world, Vector, IdDict
37
using .Core: CodeInstance, MethodInstance
4-
using .Base: JLOptions, Compiler, get_world_counter, _methods_by_ftype, get_methodtable, get_ci_mi, morespecific
58

69
const WORLD_AGE_REVALIDATION_SENTINEL::UInt = 1
7-
const _jl_debug_method_invalidation = Ref{Union{Nothing,Vector{Any}}}(nothing)
10+
const _jl_debug_method_invalidation = RefValue{Union{Nothing,Vector{Any}}}(nothing)
811
debug_method_invalidation(onoff::Bool) =
912
_jl_debug_method_invalidation[] = onoff ? Any[] : nothing
1013

@@ -70,7 +73,7 @@ function insert_backedges(edges::Vector{Any}, ext_ci_list::Union{Nothing,Vector{
7073
# determine which CodeInstance objects are still valid in our image
7174
# to enable any applicable new codes
7275
backedges_only = unsafe_load(cglobal(:jl_first_image_replacement_world, UInt)) == typemax(UInt)
73-
Base.scan_new_methods!(extext_methods, internal_methods, backedges_only)
76+
scan_new_methods!(extext_methods, internal_methods, backedges_only)
7477
workspace = VerifyMethodWorkspace()
7578
_insert_backedges(edges, workspace)
7679
if ext_ci_list !== nothing
@@ -135,23 +138,23 @@ function needs_instrumentation(codeinst::CodeInstance, mi::MethodInstance, def::
135138
if JLOptions().code_coverage != 0 || JLOptions().malloc_log != 0
136139
# test if the code needs to run with instrumentation, in which case we cannot use existing generated code
137140
if isdefined(def, :debuginfo) ? # generated_only functions do not have debuginfo, so fall back to considering their codeinst debuginfo though this may be slower and less reliable
138-
Compiler.should_instrument(def.module, def.debuginfo) :
139-
isdefined(codeinst, :debuginfo) && Compiler.should_instrument(def.module, codeinst.debuginfo)
141+
should_instrument(def.module, def.debuginfo) :
142+
isdefined(codeinst, :debuginfo) && should_instrument(def.module, codeinst.debuginfo)
140143
return true
141144
end
142145
gensig = gen_staged_sig(def, mi)
143146
if gensig !== nothing
144147
# if this is defined by a generator, try to consider forcing re-running the generators too, to add coverage for them
145-
minworld = Ref{UInt}(1)
146-
maxworld = Ref{UInt}(typemax(UInt))
147-
has_ambig = Ref{Int32}(0)
148+
minworld = RefValue{UInt}(1)
149+
maxworld = RefValue{UInt}(typemax(UInt))
150+
has_ambig = RefValue{Int32}(0)
148151
result = _methods_by_ftype(gensig, nothing, -1, validation_world, #=ambig=#false, minworld, maxworld, has_ambig)
149152
if result !== nothing
150153
for k = 1:length(result)
151154
match = result[k]::Core.MethodMatch
152155
genmethod = match.method
153156
# no, I refuse to refuse to recurse into your cursed generated function generators and will only test one level deep here
154-
if isdefined(genmethod, :debuginfo) && Compiler.should_instrument(genmethod.module, genmethod.debuginfo)
157+
if isdefined(genmethod, :debuginfo) && should_instrument(genmethod.module, genmethod.debuginfo)
155158
return true
156159
end
157160
end
@@ -194,7 +197,7 @@ function verify_method(codeinst::CodeInstance, validation_world::UInt, workspace
194197
continue
195198
end
196199

197-
minworld, maxworld = Base.get_require_world(), validation_world
200+
minworld, maxworld = get_require_world(), validation_world
198201

199202
if haskey(workspace.visiting, initial.codeinst)
200203
workspace.result_states[current_depth] = VerifyMethodResultState(workspace.visiting[initial.codeinst], minworld, maxworld)
@@ -209,7 +212,7 @@ function verify_method(codeinst::CodeInstance, validation_world::UInt, workspace
209212
# Check for invalidation of GlobalRef edges
210213
if (initial.def.did_scan_source & 0x1) == 0x0
211214
backedges_only = unsafe_load(cglobal(:jl_first_image_replacement_world, UInt)) == typemax(UInt)
212-
Base.scan_new_method!(initial.def, backedges_only)
215+
scan_new_method!(initial.def, backedges_only)
213216
end
214217
if (initial.def.did_scan_source & 0x4) != 0x0
215218
maxworld = 0
@@ -220,7 +223,7 @@ function verify_method(codeinst::CodeInstance, validation_world::UInt, workspace
220223
end
221224

222225
# Process all non-CodeInstance edges
223-
if !isempty(initial.callees) && maxworld != Base.get_require_world()
226+
if !isempty(initial.callees) && maxworld != get_require_world()
224227
matches = []
225228
j = 1
226229
while j <= length(initial.callees)
@@ -248,7 +251,7 @@ function verify_method(codeinst::CodeInstance, validation_world::UInt, workspace
248251
j += 1
249252
min_valid2 = minworld
250253
max_valid2 = maxworld
251-
if !Base.binding_was_invalidated(edge)
254+
if !binding_was_invalidated(edge)
252255
if isdefined(edge, :partitions)
253256
min_valid2 = edge.partitions.min_world
254257
max_valid2 = edge.partitions.max_world
@@ -333,7 +336,7 @@ function verify_method(codeinst::CodeInstance, validation_world::UInt, workspace
333336
end
334337
@atomic :monotonic child.max_world = result.result_maxworld
335338
if result.result_maxworld == validation_world && validation_world == get_world_counter()
336-
Compiler.store_backedges(child, child.edges)
339+
store_backedges(child, child.edges)
337340
end
338341
@assert workspace.visiting[child] == length(workspace.stack) + 1
339342
delete!(workspace.visiting, child)
@@ -559,9 +562,9 @@ function verify_call(@nospecialize(sig), expecteds::Core.SimpleVector, i::Int, n
559562
end
560563
# next, compare the current result of ml_matches to the old result
561564
lim = _jl_debug_method_invalidation[] !== nothing ? Int(typemax(Int32)) : n
562-
minworld = Ref{UInt}(1)
563-
maxworld = Ref{UInt}(typemax(UInt))
564-
has_ambig = Ref{Int32}(0)
565+
minworld = RefValue{UInt}(1)
566+
maxworld = RefValue{UInt}(typemax(UInt))
567+
has_ambig = RefValue{Int32}(0)
565568
result = _methods_by_ftype(sig, nothing, lim, world, #=ambig=#false, minworld, maxworld, has_ambig)
566569
if result === nothing
567570
empty!(matches)
@@ -626,7 +629,7 @@ function verify_invokesig(@nospecialize(invokesig), expected::Method, world::UIn
626629
minworld = 1
627630
maxworld = 0
628631
else
629-
matched, valid_worlds = Compiler._findsup(invokesig, mt, world)
632+
matched, valid_worlds = _findsup(invokesig, mt, world)
630633
minworld, maxworld = valid_worlds.min_world, valid_worlds.max_world
631634
if matched === nothing
632635
maxworld = 0
@@ -641,3 +644,9 @@ function verify_invokesig(@nospecialize(invokesig), expected::Method, world::UIn
641644
end
642645
return minworld, maxworld
643646
end
647+
648+
# Wrapper to call insert_backedges in typeinf_world for external calls
649+
function insert_backedges_typeinf(edges::Vector{Any}, ext_ci_list::Union{Nothing,Vector{Any}}, extext_methods::Vector{Any}, internal_methods::Vector{Any})
650+
args = Any[insert_backedges, edges, ext_ci_list, extext_methods, internal_methods]
651+
return ccall(:jl_call_in_typeinf_world, Any, (Ptr{Any}, Cint), args, length(args))
652+
end

Compiler/src/typeinfer.jl

Lines changed: 7 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -741,6 +741,13 @@ function Base.iterate(it::ForwardToBackedgeIterator, i::Int = 1)
741741
end
742742

743743
# record the backedges
744+
745+
function maybe_add_binding_backedge!(b::Core.Binding, edge::Union{Method, CodeInstance})
746+
meth = isa(edge, Method) ? edge : get_ci_mi(edge).def
747+
ccall(:jl_maybe_add_binding_backedge, Cint, (Any, Any, Any), b, edge, meth)
748+
return nothing
749+
end
750+
744751
function store_backedges(caller::CodeInstance, edges::SimpleVector)
745752
isa(get_ci_mi(caller).def, Method) || return # don't add backedges to toplevel method instance
746753

base/Base.jl

Lines changed: 0 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -267,9 +267,6 @@ include("uuid.jl")
267267
include("pkgid.jl")
268268
include("toml_parser.jl")
269269
include("linking.jl")
270-
module StaticData
271-
include("staticdata.jl")
272-
end
273270
include("loading.jl")
274271

275272
# BinaryPlatforms, used by Artifacts. Needs `Sort`.

base/Base_compiler.jl

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -348,7 +348,6 @@ using .Order
348348

349349
include("coreir.jl")
350350
include("module.jl")
351-
include("invalidation.jl")
352351

353352
BUILDROOT::String = ""
354353
DATAROOT::String = ""
@@ -377,6 +376,7 @@ process_sysimg_args!()
377376
function isready end
378377

379378
include(strcat(DATAROOT, "julia/Compiler/src/Compiler.jl"))
379+
using .Compiler.ReinferUtils: ReinferUtils, invalidate_code_for_globalref!
380380

381381
const _return_type = Compiler.return_type
382382

base/c.jl

Lines changed: 10 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -226,16 +226,16 @@ function expand_ccallable(name, rt, def)
226226
else
227227
f = :(typeof($f))
228228
end
229-
at = map(sig.args[2:end]) do a
230-
if isa(a,Expr) && a.head === :(::)
231-
a.args[end]
232-
else
233-
:Any
234-
end
235-
end
229+
at = Any[let a = sig.args[i]
230+
if isa(a,Expr) && a.head === :(::)
231+
a.args[end]
232+
else
233+
:Any
234+
end
235+
end for i in 2:length(sig.args)]
236236
return quote
237237
@__doc__ $(esc(def))
238-
_ccallable($name, $(esc(rt)), $(Expr(:curly, :Tuple, esc(f), map(esc, at)...)))
238+
_ccallable($name, $(esc(rt)), $(Expr(:curly, :Tuple, esc(f), map!(esc, at, at)...)))
239239
end
240240
end
241241
end
@@ -349,7 +349,7 @@ function ccall_macro_parse(exprs)
349349
end
350350
# add any varargs if necessary
351351
nreq = 0
352-
if !isnothing(varargs)
352+
if varargs !== nothing
353353
if length(args) == 0
354354
throw(ArgumentError("C ABI prohibits vararg without one required argument"))
355355
end
@@ -389,7 +389,7 @@ function ccall_macro_lower(convention, func, rettype, types, args, gc_safe, nreq
389389

390390
return Expr(:block, statements...,
391391
Expr(:call, :ccall, func, cconv, esc(rettype),
392-
Expr(:tuple, map(esc, types)...), map(esc, args)...))
392+
Expr(:tuple, map!(esc, types, types)...), map!(esc, args, args)...))
393393
end
394394

395395
"""

base/loading.jl

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1288,7 +1288,7 @@ function _include_from_serialized(pkg::PkgId, path::String, ocachepath::Union{No
12881288
extext_methods = sv[5]::Vector{Any}
12891289
internal_methods = sv[6]::Vector{Any}
12901290
Compiler.@zone "CC: INSERT_BACKEDGES" begin
1291-
StaticData.insert_backedges(edges, ext_edges, extext_methods, internal_methods)
1291+
ReinferUtils.insert_backedges_typeinf(edges, ext_edges, extext_methods, internal_methods)
12921292
end
12931293
restored = register_restored_modules(sv, pkg, path)
12941294

sysimage.mk

Lines changed: 0 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -57,7 +57,6 @@ COMPILER_SRCS := $(addprefix $(JULIAHOME)/, \
5757
base/int.jl \
5858
base/indices.jl \
5959
base/iterators.jl \
60-
base/invalidation.jl \
6160
base/module.jl \
6261
base/namedtuple.jl \
6362
base/ntuple.jl \

test/precompile.jl

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1055,9 +1055,9 @@ precompile_test_harness("code caching") do dir
10551055
const glbi = LogBindingInvalidation(2.0)
10561056
end)
10571057
@eval using $StaleC
1058-
invalidations = Base.StaticData.debug_method_invalidation(true)
1058+
invalidations = Base.ReinferUtils.debug_method_invalidation(true)
10591059
@eval using $StaleB
1060-
Base.StaticData.debug_method_invalidation(false)
1060+
Base.ReinferUtils.debug_method_invalidation(false)
10611061
invokelatest() do
10621062
MB = getfield(@__MODULE__, StaleB)
10631063
MC = getfield(@__MODULE__, StaleC)

0 commit comments

Comments
 (0)