Skip to content

Commit fc7c7b7

Browse files
committed
trimming: follow-ups to finalizer support
1 parent dd392bf commit fc7c7b7

File tree

3 files changed

+54
-22
lines changed

3 files changed

+54
-22
lines changed

Compiler/src/typeinfer.jl

Lines changed: 11 additions & 12 deletions
Original file line numberDiff line numberDiff line change
@@ -1493,29 +1493,28 @@ const TRIM_UNSAFE = 2
14931493
const TRIM_UNSAFE_WARN = 3
14941494
function typeinf_ext_toplevel(methods::Vector{Any}, worlds::Vector{UInt}, trim_mode::Int)
14951495
inf_params = InferenceParams(; force_enable_inference = trim_mode != TRIM_NO)
1496+
1497+
# Create an "invokelatest" queue to enable eager compilation of speculative
1498+
# invokelatest calls such as from `Core.finalizer` and `ccallable`
14961499
invokelatest_queue = CompilationQueue(;
14971500
interp = NativeInterpreter(get_world_counter(); inf_params)
14981501
)
1502+
14991503
codeinfos = []
1500-
is_latest_world = true # whether this_world == world_counter()
15011504
workqueue = CompilationQueue(; interp = nothing)
15021505
for this_world in reverse!(sort!(worlds))
15031506
workqueue = CompilationQueue(workqueue;
15041507
interp = NativeInterpreter(this_world; inf_params)
15051508
)
15061509

15071510
append!(workqueue, methods)
1508-
if is_latest_world
1509-
# Provide the `invokelatest` queue so that we trigger "best-effort" code generation
1510-
# for, e.g., finalizers and cfunction.
1511-
#
1512-
# The queue is intentionally aliased, to handle e.g. a `finalizer` calling `Core.finalizer`
1513-
# (it will enqueue into itself and immediately drain)
1514-
compile!(codeinfos, workqueue; invokelatest_queue = workqueue)
1515-
else
1516-
compile!(codeinfos, workqueue)
1517-
end
1518-
is_latest_world = false
1511+
compile!(codeinfos, workqueue; invokelatest_queue)
1512+
end
1513+
1514+
if invokelatest_queue !== nothing
1515+
# This queue is intentionally aliased, to handle e.g. a `finalizer` calling `Core.finalizer`
1516+
# (it will enqueue into itself and immediately drain)
1517+
compile!(codeinfos, invokelatest_queue; invokelatest_queue)
15191518
end
15201519

15211520
if trim_mode != TRIM_NO && trim_mode != TRIM_UNSAFE

Compiler/src/verifytrim.jl

Lines changed: 25 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -15,9 +15,9 @@ using ..Compiler:
1515
hasintersect, haskey, in, isdispatchelem, isempty, isexpr, iterate, length, map!, max,
1616
pop!, popfirst!, push!, pushfirst!, reinterpret, reverse!, reverse, setindex!,
1717
setproperty!, similar, singleton_type, sptypes_from_meth_instance,
18-
unsafe_pointer_to_objref, widenconst,
18+
unsafe_pointer_to_objref, widenconst, isconcretetype,
1919
# misc
20-
@nospecialize, C_NULL
20+
@nospecialize, @assert, C_NULL
2121
using ..IRShow: LineInfoNode, print, show, println, append_scopes!, IOContext, IO, normalize_method_name
2222
using ..Base: Base, sourceinfo_slotnames
2323
using ..Base.StackTraces: StackFrame
@@ -166,7 +166,7 @@ function may_dispatch(@nospecialize ftyp)
166166
end
167167
end
168168

169-
function verify_codeinstance!(codeinst::CodeInstance, codeinfo::CodeInfo, inspected::IdSet{CodeInstance}, caches::IdDict{MethodInstance,CodeInstance}, parents::ParentMap, errors::ErrorList)
169+
function verify_codeinstance!(interp::NativeInterpreter, codeinst::CodeInstance, codeinfo::CodeInfo, inspected::IdSet{CodeInstance}, caches::IdDict{MethodInstance,CodeInstance}, parents::ParentMap, errors::ErrorList)
170170
mi = get_ci_mi(codeinst)
171171
sptypes = sptypes_from_meth_instance(mi)
172172
src = codeinfo.code
@@ -199,9 +199,9 @@ function verify_codeinstance!(codeinst::CodeInstance, codeinfo::CodeInfo, inspec
199199
if !may_dispatch(ftyp)
200200
continue
201201
end
202-
# TODO: Make interp elsewhere
203-
interp = NativeInterpreter(Base.get_world_counter())
204-
if Core._apply_iterate isa ftyp
202+
if !isconcretetype(ftyp)
203+
error = "unresolved call to (unknown) builtin"
204+
elseif Core._apply_iterate isa ftyp
205205
if length(stmt.args) >= 3
206206
# args[1] is _apply_iterate object
207207
# args[2] is invoke object
@@ -233,9 +233,23 @@ function verify_codeinstance!(codeinst::CodeInstance, codeinfo::CodeInfo, inspec
233233

234234
error = "unresolved finalizer registered"
235235
end
236-
else
237-
error = "unresolved call to builtin"
238-
end
236+
elseif Core._apply isa ftyp
237+
error = "trim verification not yet implemented for builtin `Core._apply`"
238+
elseif Core._call_in_world_total isa ftyp
239+
error = "trim verification not yet implemented for builtin `Core._call_in_world_total`"
240+
elseif Core.invoke isa ftyp
241+
error = "trim verification not yet implemented for builtin `Core.invoke`"
242+
elseif Core.invoke_in_world isa ftyp
243+
error = "trim verification not yet implemented for builtin `Core.invoke_in_world`"
244+
elseif Core.invokelatest isa ftyp
245+
error = "trim verification not yet implemented for builtin `Core.invokelatest`"
246+
elseif Core.modifyfield! isa ftyp
247+
error = "trim verification not yet implemented for builtin `Core.modifyfield!`"
248+
elseif Core.modifyglobal! isa ftyp
249+
error = "trim verification not yet implemented for builtin `Core.modifyglobal!`"
250+
elseif Core.memoryrefmodify! isa ftyp
251+
error = "trim verification not yet implemented for builtin `Core.memoryrefmodify!`"
252+
else @assert false "unexpected builtin" end
239253
end
240254
extyp = argextype(SSAValue(i), codeinfo, sptypes)
241255
if extyp === Union{}
@@ -267,6 +281,7 @@ end
267281

268282
function get_verify_typeinf_trim(codeinfos::Vector{Any})
269283
this_world = get_world_counter()
284+
interp = NativeInterpreter(this_world)
270285
inspected = IdSet{CodeInstance}()
271286
caches = IdDict{MethodInstance,CodeInstance}()
272287
errors = ErrorList()
@@ -287,7 +302,7 @@ function get_verify_typeinf_trim(codeinfos::Vector{Any})
287302
item = codeinfos[i]
288303
if item isa CodeInstance
289304
src = codeinfos[i + 1]::CodeInfo
290-
verify_codeinstance!(item, src, inspected, caches, parents, errors)
305+
verify_codeinstance!(interp, item, src, inspected, caches, parents, errors)
291306
elseif item isa SimpleVector
292307
rt = item[1]::Type
293308
sig = item[2]::Type

Compiler/test/verifytrim.jl

Lines changed: 18 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -18,6 +18,24 @@ let infos = Any[]
1818
@test isempty(parents)
1919
end
2020

21+
finalizer(@nospecialize(f), @nospecialize(o)) = Core.finalizer(f, o)
22+
23+
let infos = typeinf_ext_toplevel(Any[Core.svec(Nothing, Tuple{typeof(finalizer), typeof(identity), Any})], [Base.get_world_counter()], TRIM_UNSAFE)
24+
errors, parents = get_verify_typeinf_trim(infos)
25+
@test !isempty(errors) # unresolvable finalizer
26+
27+
# the only error should be a CallMissing error for the Core.finalizer builtin
28+
(warn, desc) = only(errors)
29+
@test !warn
30+
@test desc isa CallMissing
31+
@test occursin("finalizer", desc.desc)
32+
repr = sprint(verify_print_error, desc, parents)
33+
@test occursin(
34+
r"""^unresolved finalizer registered from statement \(Core.finalizer\)\(f::Any, o::Any\)::Nothing
35+
Stacktrace:
36+
\[1\] finalizer\(f::Any, o::Any\)""", repr)
37+
end
38+
2139
make_cfunction() = @cfunction(+, Float64, (Int64,Int64))
2240

2341
# use TRIM_UNSAFE to bypass verifier inside typeinf_ext_toplevel

0 commit comments

Comments
 (0)