Skip to content

Commit 3efd841

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 6bab302 commit 3efd841

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
@@ -1255,8 +1255,29 @@ function typeinf_type(interp::AbstractInterpreter, mi::MethodInstance)
12551255
return ci.rettype
12561256
end
12571257

1258+
# Resolve a call, as described by `argtype` to a single matching
1259+
# Method and return a compilable MethodInstance for the call, if
1260+
# it will be runtime-dispatched to exactly that MethodInstance
1261+
function compileable_specialization_for_call(interp::AbstractInterpreter, @nospecialize(argtype))
1262+
matches = findall(argtype, method_table(interp); limit = 1)
1263+
matches === nothing && return nothing
1264+
length(matches.matches) == 0 && return nothing
1265+
match = only(matches.matches)
1266+
1267+
compileable_atype = get_compileable_sig(match.method, match.spec_types, match.sparams)
1268+
compileable_atype === nothing && return nothing
1269+
if match.spec_types !== compileable_atype
1270+
sp_ = ccall(:jl_type_intersection_with_env, Any, (Any, Any), compileable_atype, method.sig)::SimpleVector
1271+
sparams = sp_[2]::SimpleVector
1272+
mi = specialize_method(match.method, compileable_atype, sparams)
1273+
else
1274+
mi = specialize_method(match.method, compileable_atype, match.sparams)
1275+
end
1276+
return mi
1277+
end
1278+
12581279
# collect a list of all code that is needed along with CodeInstance to codegen it fully
1259-
function collectinvokes!(wq::Vector{CodeInstance}, ci::CodeInfo)
1280+
function collectinvokes!(wq::Vector{CodeInstance}, ci::CodeInfo, sptypes::Vector{VarState})
12601281
src = ci.code
12611282
for i = 1:length(src)
12621283
stmt = src[i]
@@ -1265,6 +1286,31 @@ function collectinvokes!(wq::Vector{CodeInstance}, ci::CodeInfo)
12651286
edge = stmt.args[1]
12661287
edge isa CodeInstance && isdefined(edge, :inferred) && push!(wq, edge)
12671288
end
1289+
1290+
if isexpr(stmt, :call)
1291+
farg = stmt.args[1]
1292+
!applicable(argextype, farg, ci, sptypes) && continue # TODO: Why is this failing during bootstrap
1293+
ftyp = widenconst(argextype(farg, ci, sptypes))
1294+
if ftyp <: Builtin
1295+
# TODO: Make interp elsewhere
1296+
interp = NativeInterpreter(Base.get_world_counter())
1297+
if Core.finalizer isa ftyp && length(stmt.args) == 3
1298+
finalizer = argextype(stmt.args[2], ci, sptypes)
1299+
obj = argextype(stmt.args[3], ci, sptypes)
1300+
atype = argtypes_to_type(Any[finalizer, obj])
1301+
1302+
mi = compileable_specialization_for_call(interp, atype)
1303+
mi === nothing && continue
1304+
1305+
if mi.def.primary_world <= Base.get_world_counter() <= mi.def.deleted_world
1306+
ci = typeinf_ext(interp, mi, SOURCE_MODE_GET_SOURCE)
1307+
# TODO: separate workqueue for NativeInterpreter
1308+
ci isa CodeInstance && push!(wq, ci)
1309+
end
1310+
# push!(wq, mi)
1311+
end
1312+
end
1313+
end
12681314
# TODO: handle other StmtInfo like @cfunction and OpaqueClosure?
12691315
end
12701316
end
@@ -1301,8 +1347,9 @@ function add_codeinsts_to_jit!(interp::AbstractInterpreter, ci, source_mode::UIn
13011347
end
13021348
end
13031349
push!(inspected, callee)
1304-
collectinvokes!(tocompile, src)
13051350
mi = get_ci_mi(callee)
1351+
sptypes = sptypes_from_meth_instance(mi)
1352+
collectinvokes!(tocompile, src, sptypes)
13061353
if iszero(ccall(:jl_mi_cache_has_ci, Cint, (Any, Any), mi, callee))
13071354
cached = ccall(:jl_get_ci_equiv, Any, (Any, UInt), callee, get_inference_world(interp))::CodeInstance
13081355
if cached === callee
@@ -1400,7 +1447,8 @@ function typeinf_ext_toplevel(methods::Vector{Any}, worlds::Vector{UInt}, trim_m
14001447
end
14011448
push!(inspected, callee)
14021449
if src isa CodeInfo
1403-
collectinvokes!(tocompile, src)
1450+
sptypes = sptypes_from_meth_instance(mi)
1451+
collectinvokes!(tocompile, src, sptypes)
14041452
# try to reuse an existing CodeInstance from before to avoid making duplicates in the cache
14051453
if iszero(ccall(:jl_mi_cache_has_ci, Cint, (Any, Any), mi, callee))
14061454
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
@@ -3229,6 +3229,7 @@ JL_DLLEXPORT jl_method_instance_t *jl_method_match_to_mi(jl_method_match_t *matc
32293229
}
32303230

32313231
// compile-time method lookup
3232+
// intersect types with the MT, and return a single compileable specialization that covers the intersection.
32323233
jl_method_instance_t *jl_get_specialization1(jl_tupletype_t *types, size_t world, int mt_cache)
32333234
{
32343235
if (jl_has_free_typevars((jl_value_t*)types))

0 commit comments

Comments
 (0)