Skip to content

Commit fc1113f

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 f9f5f6e commit fc1113f

File tree

4 files changed

+77
-6
lines changed

4 files changed

+77
-6
lines changed

Compiler/src/typeinfer.jl

Lines changed: 57 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -1243,8 +1243,29 @@ function typeinf_type(interp::AbstractInterpreter, mi::MethodInstance)
12431243
return ci.rettype
12441244
end
12451245

1246+
# Resolve a call, as described by `argtype` to a single matching
1247+
# Method and return a compilable MethodInstance for the call, if
1248+
# it will be runtime-dispatched to exactly that MethodInstance
1249+
function compileable_specialization_for_call(interp::AbstractInterpreter, @nospecialize(argtype))
1250+
matches = findall(argtype, method_table(interp); limit = 1)
1251+
matches === nothing && return nothing
1252+
length(matches.matches) == 0 && return nothing
1253+
match = only(matches.matches)
1254+
1255+
compileable_atype = get_compileable_sig(match.method, match.spec_types, match.sparams)
1256+
compileable_atype === nothing && return nothing
1257+
if match.spec_types !== compileable_atype
1258+
sp_ = ccall(:jl_type_intersection_with_env, Any, (Any, Any), compileable_atype, method.sig)::SimpleVector
1259+
sparams = sp_[2]::SimpleVector
1260+
mi = specialize_method(match.method, compileable_atype, sparams)
1261+
else
1262+
mi = specialize_method(match.method, compileable_atype, match.sparams)
1263+
end
1264+
return mi
1265+
end
1266+
12461267
# collect a list of all code that is needed along with CodeInstance to codegen it fully
1247-
function collectinvokes!(wq::Vector{CodeInstance}, ci::CodeInfo)
1268+
function collectinvokes!(wq::Vector{CodeInstance}, ci::CodeInfo, sptypes::Vector{VarState}, seen::Union{Nothing,IdSet{MethodInstance}})
12481269
src = ci.code
12491270
for i = 1:length(src)
12501271
stmt = src[i]
@@ -1253,6 +1274,34 @@ function collectinvokes!(wq::Vector{CodeInstance}, ci::CodeInfo)
12531274
edge = stmt.args[1]
12541275
edge isa CodeInstance && isdefined(edge, :inferred) && push!(wq, edge)
12551276
end
1277+
1278+
if isexpr(stmt, :call) && seen !== nothing
1279+
farg = stmt.args[1]
1280+
!applicable(argextype, farg, ci, sptypes) && continue # TODO: Why is this failing during bootstrap
1281+
ftyp = widenconst(argextype(farg, ci, sptypes))
1282+
if ftyp <: Builtin
1283+
# TODO: Make interp elsewhere
1284+
interp = NativeInterpreter(Base.get_world_counter())
1285+
if Core.finalizer isa ftyp && length(stmt.args) == 3
1286+
finalizer = argextype(stmt.args[2], ci, sptypes)
1287+
obj = argextype(stmt.args[3], ci, sptypes)
1288+
atype = argtypes_to_type(Any[finalizer, obj])
1289+
1290+
mi = compileable_specialization_for_call(interp, atype)
1291+
mi === nothing && continue
1292+
1293+
mi in seen && continue
1294+
push!(seen, mi)
1295+
1296+
if mi.def.primary_world <= Base.get_world_counter() <= mi.def.deleted_world
1297+
ci = typeinf_ext(interp, mi, SOURCE_MODE_NOT_REQUIRED)
1298+
# TODO: separate workqueue for NativeInterpreter
1299+
ci isa CodeInstance && push!(wq, ci)
1300+
end
1301+
# push!(wq, mi)
1302+
end
1303+
end
1304+
end
12561305
# TODO: handle other StmtInfo like @cfunction and OpaqueClosure?
12571306
end
12581307
end
@@ -1289,7 +1338,10 @@ function add_codeinsts_to_jit!(interp::AbstractInterpreter, ci, source_mode::UIn
12891338
end
12901339
end
12911340
push!(inspected, callee)
1292-
collectinvokes!(tocompile, src)
1341+
mi = get_ci_mi(callee)
1342+
sptypes = sptypes_from_meth_instance(mi)
1343+
collectinvokes!(tocompile, src, sptypes, nothing)
1344+
# collectinvokes!(tocompile, src)
12931345
mi = get_ci_mi(callee)
12941346
if iszero(ccall(:jl_mi_cache_has_ci, Cint, (Any, Any), mi, callee))
12951347
cached = ccall(:jl_get_ci_equiv, Any, (Any, UInt), callee, get_inference_world(interp))::CodeInstance
@@ -1328,6 +1380,7 @@ const TRIM_UNSAFE_WARN = 3
13281380
function typeinf_ext_toplevel(methods::Vector{Any}, worlds::Vector{UInt}, trim_mode::Int)
13291381
inspected = IdSet{CodeInstance}()
13301382
tocompile = Vector{CodeInstance}()
1383+
inspected_mis = IdSet{MethodInstance}()
13311384
codeinfos = []
13321385
# first compute the ABIs of everything
13331386
latest = true # whether this_world == world_counter()
@@ -1389,7 +1442,8 @@ function typeinf_ext_toplevel(methods::Vector{Any}, worlds::Vector{UInt}, trim_m
13891442
end
13901443
push!(inspected, callee)
13911444
if src isa CodeInfo
1392-
collectinvokes!(tocompile, src)
1445+
sptypes = sptypes_from_meth_instance(mi)
1446+
collectinvokes!(tocompile, src, sptypes, inspected_mis)
13931447
# try to reuse an existing CodeInstance from before to avoid making duplicates in the cache
13941448
if iszero(ccall(:jl_mi_cache_has_ci, Cint, (Any, Any), mi, callee))
13951449
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
@@ -1570,12 +1570,18 @@ end
15701570

15711571
is_nospecialized(method::Method) = method.nospecialize 0
15721572
is_nospecializeinfer(method::Method) = method.nospecializeinfer && is_nospecialized(method)
1573+
1574+
"""
1575+
Return MethodInstance corresponding to `atype` and `sparams`.
1576+
1577+
No widening / narrowing / compileable-normalization of `atype` is performed.
1578+
"""
15731579
function specialize_method(method::Method, @nospecialize(atype), sparams::SimpleVector; preexisting::Bool=false)
15741580
@inline
15751581
if isa(atype, UnionAll)
15761582
atype, sparams = normalize_typevars(method, atype, sparams)
15771583
end
1578-
if is_nospecializeinfer(method)
1584+
if is_nospecializeinfer(method) # TODO: this shouldn't be here
15791585
atype = get_nospecializeinfer_sig(method, atype, sparams)
15801586
end
15811587
if preexisting

src/gf.c

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

32213221
// compile-time method lookup
3222+
// intersect types with the MT, and return a single compileable specialization that covers the intersection.
32223223
jl_method_instance_t *jl_get_specialization1(jl_tupletype_t *types, size_t world, int mt_cache)
32233224
{
32243225
if (jl_has_free_typevars((jl_value_t*)types))

0 commit comments

Comments
 (0)