|
| 1 | +""" |
| 2 | + @recompile_invalidations begin |
| 3 | + using PkgA |
| 4 | + ⋮ |
| 5 | + end |
| 6 | +
|
| 7 | +Recompile any invalidations that occur within the given expression. This is generally intended to be used |
| 8 | +by users in creating "Startup" packages to ensure that the code compiled by package authors is not invalidated. |
| 9 | +""" |
| 10 | +macro recompile_invalidations(expr) |
| 11 | + list = gensym(:list) |
| 12 | + Expr(:toplevel, |
| 13 | + :($list = ccall(:jl_debug_method_invalidation, Any, (Cint,), 1)), |
| 14 | + Expr(:tryfinally, |
| 15 | + esc(expr), |
| 16 | + :(ccall(:jl_debug_method_invalidation, Any, (Cint,), 0)) |
| 17 | + ), |
| 18 | + :(if ccall(:jl_generating_output, Cint, ()) == 1 |
| 19 | + foreach($precompile_mi, $invalidation_leaves($list)) |
| 20 | + end) |
| 21 | + ) |
| 22 | +end |
| 23 | + |
| 24 | +function precompile_mi(mi) |
| 25 | + precompile(mi.specTypes) # TODO: Julia should allow one to pass `mi` directly (would handle `invoke` properly) |
| 26 | + return |
| 27 | +end |
| 28 | + |
| 29 | +function invalidation_leaves(invlist) |
| 30 | + umis = Set{Core.MethodInstance}() |
| 31 | + # `queued` is a queue of length 0 or 1 of invalidated MethodInstances. |
| 32 | + # We wait to read the `depth` to find out if it's a leaf. |
| 33 | + queued, depth = nothing, 0 |
| 34 | + function cachequeued(item, nextdepth) |
| 35 | + if queued !== nothing && nextdepth <= depth |
| 36 | + push!(umis, queued) |
| 37 | + end |
| 38 | + queued, depth = item, nextdepth |
| 39 | + end |
| 40 | + |
| 41 | + i, ilast = firstindex(invlist), lastindex(invlist) |
| 42 | + while i <= ilast |
| 43 | + item = invlist[i] |
| 44 | + if isa(item, Core.MethodInstance) |
| 45 | + if i < lastindex(invlist) |
| 46 | + nextitem = invlist[i+1] |
| 47 | + if nextitem == "invalidate_mt_cache" |
| 48 | + cachequeued(nothing, 0) |
| 49 | + i += 2 |
| 50 | + continue |
| 51 | + end |
| 52 | + if nextitem ∈ ("jl_method_table_disable", "jl_method_table_insert", "verify_methods") |
| 53 | + cachequeued(nothing, 0) |
| 54 | + push!(umis, item) |
| 55 | + end |
| 56 | + if isa(nextitem, Integer) |
| 57 | + cachequeued(item, nextitem) |
| 58 | + i += 2 |
| 59 | + continue |
| 60 | + end |
| 61 | + end |
| 62 | + end |
| 63 | + if (isa(item, Method) || isa(item, Type)) && queued !== nothing |
| 64 | + push!(umis, queued) |
| 65 | + queued, depth = nothing, 0 |
| 66 | + end |
| 67 | + i += 1 |
| 68 | + end |
| 69 | + return umis |
| 70 | +end |
0 commit comments