Skip to content

Commit 4f975b0

Browse files
vchuravyaviatesk
andcommitted
Tag CodeInstance for external abstract interpreter
External abstract interpreters need to be able to take part in invalidation, as well as cross-session inference result caching. MethodInstance.cache contains a set of CodeInstances which hold the inference cache results. Instead of haveing external abstract interpreters create detached CodeInstances we attach them the the MethodInstance they were created from. This solves the invalidation problem and the cross-session cache problem in one go, but requires that we tag/mark the CodeInstance with a token to remember which abstract interpreter created them. `nothing` is reserved for the native interpreter and all other interpreters can use values that compare with `jl_egal`. To perform a cache-lookup we need the current abstract interpreter token. Co-authored-by: Shuhei Kadowaki <40514306+aviatesk@users.noreply.github.com>
1 parent 3dadada commit 4f975b0

25 files changed

+345
-260
lines changed

base/boot.jl

Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -483,13 +483,13 @@ eval(Core, quote
483483
end)
484484

485485
function CodeInstance(
486-
mi::MethodInstance, @nospecialize(rettype), @nospecialize(exctype), @nospecialize(inferred_const),
486+
mi::MethodInstance, owner, @nospecialize(rettype), @nospecialize(exctype), @nospecialize(inferred_const),
487487
@nospecialize(inferred), const_flags::Int32, min_world::UInt, max_world::UInt,
488488
ipo_effects::UInt32, effects::UInt32, @nospecialize(analysis_results),
489489
relocatability::UInt8)
490490
return ccall(:jl_new_codeinst, Ref{CodeInstance},
491-
(Any, Any, Any, Any, Any, Int32, UInt, UInt, UInt32, UInt32, Any, UInt8),
492-
mi, rettype, exctype, inferred_const, inferred, const_flags, min_world, max_world,
491+
(Any, Any, Any, Any, Any, Any, Int32, UInt, UInt, UInt32, UInt32, Any, UInt8),
492+
mi, owner, rettype, exctype, inferred_const, inferred, const_flags, min_world, max_world,
493493
ipo_effects, effects, analysis_results,
494494
relocatability)
495495
end

base/compiler/cicache.jl

Lines changed: 7 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -7,14 +7,17 @@ Internally, each `MethodInstance` keep a unique global cache of code instances
77
that have been created for the given method instance, stratified by world age
88
ranges. This struct abstracts over access to this cache.
99
"""
10-
struct InternalCodeCache end
10+
struct InternalCodeCache
11+
owner::Any # `jl_egal` is used for comparison
12+
end
1113

1214
function setindex!(cache::InternalCodeCache, ci::CodeInstance, mi::MethodInstance)
15+
@assert ci.owner === cache.owner
1316
ccall(:jl_mi_cache_insert, Cvoid, (Any, Any), mi, ci)
1417
return cache
1518
end
1619

17-
const GLOBAL_CI_CACHE = InternalCodeCache()
20+
const GLOBAL_CI_CACHE = InternalCodeCache(nothing)
1821

1922
struct WorldRange
2023
min_world::UInt
@@ -49,11 +52,11 @@ WorldView(wvc::WorldView, wr::WorldRange) = WorldView(wvc.cache, wr)
4952
WorldView(wvc::WorldView, args...) = WorldView(wvc.cache, args...)
5053

5154
function haskey(wvc::WorldView{InternalCodeCache}, mi::MethodInstance)
52-
return ccall(:jl_rettype_inferred, Any, (Any, UInt, UInt), mi, first(wvc.worlds), last(wvc.worlds)) !== nothing
55+
return ccall(:jl_rettype_inferred, Any, (Any, Any, UInt, UInt), wvc.cache.owner, mi, first(wvc.worlds), last(wvc.worlds)) !== nothing
5356
end
5457

5558
function get(wvc::WorldView{InternalCodeCache}, mi::MethodInstance, default)
56-
r = ccall(:jl_rettype_inferred, Any, (Any, UInt, UInt), mi, first(wvc.worlds), last(wvc.worlds))
59+
r = ccall(:jl_rettype_inferred, Any, (Any, Any, UInt, UInt), wvc.cache.owner, mi, first(wvc.worlds), last(wvc.worlds))
5760
if r === nothing
5861
return default
5962
end

base/compiler/typeinfer.jl

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -326,7 +326,7 @@ function CodeInstance(interp::AbstractInterpreter, result::InferenceResult,
326326
end
327327
end
328328
# relocatability = isa(inferred_result, String) ? inferred_result[end] : UInt8(0)
329-
return CodeInstance(result.linfo,
329+
return CodeInstance(result.linfo, cache_owner(interp),
330330
widenconst(result_type), widenconst(result.exc_result), rettype_const, inferred_result,
331331
const_flags, first(valid_worlds), last(valid_worlds),
332332
# TODO: Actually do something with non-IPO effects

base/compiler/types.jl

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -14,6 +14,7 @@ the following methods to satisfy the `AbstractInterpreter` API requirement:
1414
- `OptimizationParams(interp::NewInterpreter)` - return an `OptimizationParams` instance
1515
- `get_inference_world(interp::NewInterpreter)` - return the world age for this interpreter
1616
- `get_inference_cache(interp::NewInterpreter)` - return the local inference cache
17+
- `cache_owner(interp::NewInterpreter)` - return the owner of any new cache entries
1718
- `code_cache(interp::NewInterpreter)` - return the global inference cache
1819
"""
1920
:(AbstractInterpreter)
@@ -405,6 +406,7 @@ OptimizationParams(interp::NativeInterpreter) = interp.opt_params
405406
get_inference_world(interp::NativeInterpreter) = interp.world
406407
get_inference_cache(interp::NativeInterpreter) = interp.inf_cache
407408
code_cache(interp::NativeInterpreter) = WorldView(GLOBAL_CI_CACHE, get_inference_world(interp))
409+
cache_owner(interp::NativeInterpreter) = nothing
408410

409411
"""
410412
already_inferred_quick_test(::AbstractInterpreter, ::MethodInstance)

base/compiler/utilities.jl

Lines changed: 0 additions & 19 deletions
Original file line numberDiff line numberDiff line change
@@ -321,25 +321,6 @@ function iterate(iter::BackedgeIterator, i::Int=1)
321321
return BackedgePair(item, backedges[i+1]::MethodInstance), i+2 # `invoke` calls
322322
end
323323

324-
"""
325-
add_invalidation_callback!(callback, mi::MethodInstance)
326-
327-
Register `callback` to be triggered upon the invalidation of `mi`.
328-
`callback` should a function taking two arguments, `callback(replaced::MethodInstance, max_world::UInt32)`,
329-
and it will be recursively invoked on `MethodInstance`s within the invalidation graph.
330-
"""
331-
function add_invalidation_callback!(@nospecialize(callback), mi::MethodInstance)
332-
if !isdefined(mi, :callbacks)
333-
callbacks = mi.callbacks = Any[callback]
334-
else
335-
callbacks = mi.callbacks::Vector{Any}
336-
if !any(@nospecialize(cb)->cb===callback, callbacks)
337-
push!(callbacks, callback)
338-
end
339-
end
340-
return callbacks
341-
end
342-
343324
#########
344325
# types #
345326
#########

base/reflection.jl

Lines changed: 9 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1332,6 +1332,15 @@ function method_instances(@nospecialize(f), @nospecialize(t), world::UInt)
13321332
return results
13331333
end
13341334

1335+
function method_instance(@nospecialize(f), @nospecialize(t);
1336+
world=Base.get_world_counter(), method_table=nothing)
1337+
tt = signature_type(f, t)
1338+
mi = ccall(:jl_method_lookup_by_tt, Any,
1339+
(Any, Csize_t, Any),
1340+
tt, world, method_table)
1341+
return mi::Union{Nothing, MethodInstance}
1342+
end
1343+
13351344
default_debug_info_kind() = unsafe_load(cglobal(:jl_default_debug_info_kind, Cint))
13361345

13371346
# this type mirrors jl_cgparams_t (documented in julia.h)

doc/src/devdocs/ast.md

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -627,6 +627,10 @@ for important details on how to modify these fields safely.
627627

628628
The `MethodInstance` that this cache entry is derived from.
629629

630+
* `owner`
631+
632+
A token that represents the owner of this `CodeInstance`. Will use `jl_egal` to match.
633+
630634

631635
* `rettype`/`rettype_const`
632636

doc/src/devdocs/locks.md

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -155,6 +155,7 @@ MethodInstance/CodeInstance updates : Method->writelock, codegen lock
155155
> * specTypes
156156
> * sparam_vals
157157
> * def
158+
> * owner
158159
159160
> * These are set by `jl_type_infer` (while holding codegen lock):
160161
> * cache

src/builtins.c

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -2378,6 +2378,7 @@ jl_fptr_args_t jl_get_builtin_fptr(jl_datatype_t *dt)
23782378
jl_typemap_entry_t *entry = (jl_typemap_entry_t*)jl_atomic_load_relaxed(&dt->name->mt->defs);
23792379
jl_method_instance_t *mi = jl_atomic_load_relaxed(&entry->func.method->unspecialized);
23802380
jl_code_instance_t *ci = jl_atomic_load_relaxed(&mi->cache);
2381+
assert(ci->owner == jl_nothing);
23812382
return jl_atomic_load_relaxed(&ci->specptr.fptr1);
23822383
}
23832384

0 commit comments

Comments
 (0)