Skip to content

Commit ea6a465

Browse files
committed
trim: Add Core.finalizer support
This adds the changes required to guess the MethodInstance that the runtime will eventually invoke for this call, enqueue it for codegen, and then verify its presence in the verifier.
1 parent ccef01a commit ea6a465

File tree

4 files changed

+71
-6
lines changed

4 files changed

+71
-6
lines changed

Compiler/src/typeinfer.jl

Lines changed: 51 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -1374,8 +1374,29 @@ function typeinf_type(interp::AbstractInterpreter, mi::MethodInstance)
13741374
return ci.rettype
13751375
end
13761376

1377+
# Resolve a call, as described by `argtype` to a single matching
1378+
# Method and return a compilable MethodInstance for the call, if
1379+
# it will be runtime-dispatched to exactly that MethodInstance
1380+
function compileable_specialization_for_call(interp::AbstractInterpreter, @nospecialize(argtype))
1381+
matches = findall(argtype, method_table(interp); limit = 1)
1382+
matches === nothing && return nothing
1383+
length(matches.matches) == 0 && return nothing
1384+
match = only(matches.matches)
1385+
1386+
compileable_atype = get_compileable_sig(match.method, match.spec_types, match.sparams)
1387+
compileable_atype === nothing && return nothing
1388+
if match.spec_types !== compileable_atype
1389+
sp_ = ccall(:jl_type_intersection_with_env, Any, (Any, Any), compileable_atype, method.sig)::SimpleVector
1390+
sparams = sp_[2]::SimpleVector
1391+
mi = specialize_method(match.method, compileable_atype, sparams)
1392+
else
1393+
mi = specialize_method(match.method, compileable_atype, match.sparams)
1394+
end
1395+
return mi
1396+
end
1397+
13771398
# collect a list of all code that is needed along with CodeInstance to codegen it fully
1378-
function collectinvokes!(wq::Vector{CodeInstance}, ci::CodeInfo)
1399+
function collectinvokes!(wq::Vector{CodeInstance}, ci::CodeInfo, sptypes::Vector{VarState})
13791400
src = ci.code
13801401
for i = 1:length(src)
13811402
stmt = src[i]
@@ -1384,6 +1405,31 @@ function collectinvokes!(wq::Vector{CodeInstance}, ci::CodeInfo)
13841405
edge = stmt.args[1]
13851406
edge isa CodeInstance && isdefined(edge, :inferred) && push!(wq, edge)
13861407
end
1408+
1409+
if isexpr(stmt, :call)
1410+
farg = stmt.args[1]
1411+
!applicable(argextype, farg, ci, sptypes) && continue # TODO: Why is this failing during bootstrap
1412+
ftyp = widenconst(argextype(farg, ci, sptypes))
1413+
if ftyp <: Builtin
1414+
# TODO: Make interp elsewhere
1415+
interp = NativeInterpreter(Base.get_world_counter())
1416+
if Core.finalizer isa ftyp && length(stmt.args) == 3
1417+
finalizer = argextype(stmt.args[2], ci, sptypes)
1418+
obj = argextype(stmt.args[3], ci, sptypes)
1419+
atype = argtypes_to_type(Any[finalizer, obj])
1420+
1421+
mi = compileable_specialization_for_call(interp, atype)
1422+
mi === nothing && continue
1423+
1424+
if mi.def.primary_world <= Base.get_world_counter() <= mi.def.deleted_world
1425+
ci = typeinf_ext(interp, mi, SOURCE_MODE_GET_SOURCE)
1426+
# TODO: separate workqueue for NativeInterpreter
1427+
ci isa CodeInstance && push!(wq, ci)
1428+
end
1429+
# push!(wq, mi)
1430+
end
1431+
end
1432+
end
13871433
# TODO: handle other StmtInfo like @cfunction and OpaqueClosure?
13881434
end
13891435
end
@@ -1420,8 +1466,9 @@ function add_codeinsts_to_jit!(interp::AbstractInterpreter, ci, source_mode::UIn
14201466
end
14211467
end
14221468
push!(inspected, callee)
1423-
collectinvokes!(tocompile, src)
14241469
mi = get_ci_mi(callee)
1470+
sptypes = sptypes_from_meth_instance(mi)
1471+
collectinvokes!(tocompile, src, sptypes)
14251472
if iszero(ccall(:jl_mi_cache_has_ci, Cint, (Any, Any), mi, callee))
14261473
cached = ccall(:jl_get_ci_equiv, Any, (Any, UInt), callee, get_inference_world(interp))::CodeInstance
14271474
if cached === callee
@@ -1519,7 +1566,8 @@ function typeinf_ext_toplevel(methods::Vector{Any}, worlds::Vector{UInt}, trim_m
15191566
end
15201567
push!(inspected, callee)
15211568
if src isa CodeInfo
1522-
collectinvokes!(tocompile, src)
1569+
sptypes = sptypes_from_meth_instance(mi)
1570+
collectinvokes!(tocompile, src, sptypes)
15231571
# try to reuse an existing CodeInstance from before to avoid making duplicates in the cache
15241572
if iszero(ccall(:jl_mi_cache_has_ci, Cint, (Any, Any), mi, callee))
15251573
cached = ccall(:jl_get_ci_equiv, Any, (Any, UInt), callee, this_world)::CodeInstance

Compiler/src/verifytrim.jl

Lines changed: 12 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -199,6 +199,8 @@ 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())
202204
if Core._apply_iterate isa ftyp
203205
if length(stmt.args) >= 3
204206
# args[1] is _apply_iterate object
@@ -219,9 +221,17 @@ function verify_codeinstance!(codeinst::CodeInstance, codeinfo::CodeInfo, inspec
219221
end
220222
elseif Core.finalizer isa ftyp
221223
if length(stmt.args) == 3
222-
# TODO: check that calling `args[1](args[2])` is defined before warning
224+
finalizer = argextype(stmt.args[2], ci, sptypes)
225+
obj = argextype(stmt.args[3], ci, sptypes)
226+
atype = argtypes_to_type(Any[finalizer, obj])
227+
228+
mi = compileable_specialization_for_call(interp, atype)
229+
if mi !== nothing
230+
ci = get(caches, mi, nothing)
231+
ci isa CodeInstance && continue
232+
end
233+
223234
error = "unresolved finalizer registered"
224-
warn = true
225235
end
226236
else
227237
error = "unresolved call to builtin"

base/runtime_internals.jl

Lines changed: 7 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1622,12 +1622,18 @@ end
16221622

16231623
is_nospecialized(method::Method) = method.nospecialize 0
16241624
is_nospecializeinfer(method::Method) = method.nospecializeinfer && is_nospecialized(method)
1625+
1626+
"""
1627+
Return MethodInstance corresponding to `atype` and `sparams`.
1628+
1629+
No widening / narrowing / compileable-normalization of `atype` is performed.
1630+
"""
16251631
function specialize_method(method::Method, @nospecialize(atype), sparams::SimpleVector; preexisting::Bool=false)
16261632
@inline
16271633
if isa(atype, UnionAll)
16281634
atype, sparams = normalize_typevars(method, atype, sparams)
16291635
end
1630-
if is_nospecializeinfer(method)
1636+
if is_nospecializeinfer(method) # TODO: this shouldn't be here
16311637
atype = get_nospecializeinfer_sig(method, atype, sparams)
16321638
end
16331639
if preexisting

src/gf.c

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -3211,6 +3211,7 @@ JL_DLLEXPORT jl_method_instance_t *jl_method_match_to_mi(jl_method_match_t *matc
32113211
}
32123212

32133213
// compile-time method lookup
3214+
// intersect types with the MT, and return a single compileable specialization that covers the intersection.
32143215
jl_method_instance_t *jl_get_specialization1(jl_tupletype_t *types, size_t world, int mt_cache)
32153216
{
32163217
if (jl_has_free_typevars((jl_value_t*)types))

0 commit comments

Comments
 (0)