@@ -35,9 +35,6 @@ function foreach_module_mtable(visit, m::Module, world::UInt)
3535 visit (mt) || return false
3636 end
3737 end
38- elseif isa (v, Module) && v != = m && parentmodule (v) === m && _nameof (v) === name
39- # this is the original/primary binding for the submodule
40- foreach_module_mtable (visit, v, world) || return false
4138 elseif isa (v, Core. MethodTable) && v. module === m && v. name === name
4239 # this is probably an external method table here, so let's
4340 # assume so as there is no way to precisely distinguish them
@@ -48,83 +45,138 @@ function foreach_module_mtable(visit, m::Module, world::UInt)
4845 return true
4946end
5047
51- function foreach_reachable_mtable (visit, world:: UInt )
52- visit (TYPE_TYPE_MT) || return
53- visit (NONFUNCTION_MT) || return
54- for mod in loaded_modules_array ()
55- foreach_module_mtable (visit, mod, world)
48+ function foreachgr (visit, src:: CodeInfo )
49+ stmts = src. code
50+ for i = 1 : length (stmts)
51+ stmt = stmts[i]
52+ isa (stmt, GlobalRef) && visit (stmt)
53+ for ur in Compiler. userefs (stmt)
54+ arg = ur[]
55+ isa (arg, GlobalRef) && visit (arg)
56+ end
5657 end
5758end
5859
59- function should_invalidate_code_for_globalref (gr:: GlobalRef , src:: CodeInfo )
60- found_any = false
61- labelchangemap = nothing
60+ function anygr (visit, src:: CodeInfo )
6261 stmts = src. code
63- isgr (g:: GlobalRef ) = gr. mod == g. mod && gr. name === g. name
64- isgr (g) = false
6562 for i = 1 : length (stmts)
6663 stmt = stmts[i]
67- if isgr (stmt)
68- found_any = true
64+ if isa (stmt, GlobalRef )
65+ visit (stmt) && return true
6966 continue
7067 end
7168 for ur in Compiler. userefs (stmt)
7269 arg = ur[]
73- # If any of the GlobalRefs in this stmt match the one that
74- # we are about, we need to move out all GlobalRefs to preserve
75- # effect order, in case we later invalidate a different GR
76- if isa (arg, GlobalRef)
77- if isgr (arg)
78- @assert ! isa (stmt, PhiNode)
79- found_any = true
80- break
81- end
82- end
70+ isa (arg, GlobalRef) && visit (arg) && return true
8371 end
8472 end
85- return found_any
73+ return false
74+ end
75+
76+ function should_invalidate_code_for_globalref (gr:: GlobalRef , src:: CodeInfo )
77+ isgr (g:: GlobalRef ) = gr. mod == g. mod && gr. name === g. name
78+ isgr (g) = false
79+ return anygr (isgr, src)
8680end
8781
88- function scan_edge_list (ci:: Core.CodeInstance , bpart :: Core.BindingPartition )
82+ function scan_edge_list (ci:: Core.CodeInstance , binding :: Core.Binding )
8983 isdefined (ci, :edges ) || return false
9084 edges = ci. edges
9185 i = 1
9286 while i <= length (edges)
93- if isassigned (edges, i) && edges[i] === bpart
87+ if isassigned (edges, i) && edges[i] === binding
9488 return true
9589 end
9690 i += 1
9791 end
9892 return false
9993end
10094
95+ function invalidate_method_for_globalref! (gr:: GlobalRef , method:: Method , invalidated_bpart:: Core.BindingPartition , new_max_world:: UInt )
96+ if isdefined (method, :source )
97+ src = _uncompressed_ir (method)
98+ binding = convert (Core. Binding, gr)
99+ old_stmts = src. code
100+ invalidate_all = should_invalidate_code_for_globalref (gr, src)
101+ for mi in specializations (method)
102+ isdefined (mi, :cache ) || continue
103+ ci = mi. cache
104+ while true
105+ if ci. max_world > new_max_world && (invalidate_all || scan_edge_list (ci, binding))
106+ ccall (:jl_invalidate_code_instance , Cvoid, (Any, UInt), ci, new_max_world)
107+ end
108+ isdefined (ci, :next ) || break
109+ ci = ci. next
110+ end
111+ end
112+ end
113+ end
114+
101115function invalidate_code_for_globalref! (gr:: GlobalRef , invalidated_bpart:: Core.BindingPartition , new_max_world:: UInt )
102116 try
103117 valid_in_valuepos = false
104- foreach_reachable_mtable ( new_max_world) do mt:: Core.MethodTable
118+ foreach_module_mtable (gr . mod, new_max_world) do mt:: Core.MethodTable
105119 for method in MethodList (mt)
106- if isdefined (method, :source )
107- src = _uncompressed_ir (method)
108- old_stmts = src. code
109- invalidate_all = should_invalidate_code_for_globalref (gr, src)
110- for mi in specializations (method)
111- isdefined (mi, :cache ) || continue
112- ci = mi. cache
113- while true
114- if ci. max_world > new_max_world && (invalidate_all || scan_edge_list (ci, invalidated_bpart))
115- ccall (:jl_invalidate_code_instance , Cvoid, (Any, UInt), ci, new_max_world)
116- end
117- isdefined (ci, :next ) || break
118- ci = ci. next
119- end
120- end
121- end
120+ invalidate_method_for_globalref! (gr, method, invalidated_bpart, new_max_world)
122121 end
123122 return true
124123 end
124+ b = convert (Core. Binding, gr)
125+ if isdefined (b, :backedges )
126+ for edge in b. backedges
127+ if isa (edge, CodeInstance)
128+ ccall (:jl_invalidate_code_instance , Cvoid, (Any, UInt), edge, new_max_world)
129+ else
130+ invalidate_method_for_globalref! (gr, edge:: Method , invalidated_bpart, new_max_world)
131+ end
132+ end
133+ end
125134 catch err
126135 bt = catch_backtrace ()
127136 invokelatest (Base. println, " Internal Error during invalidation:" )
128137 invokelatest (Base. display_error, err, bt)
129138 end
130139end
140+
141+ gr_needs_backedge_in_module (gr:: GlobalRef , mod:: Module ) = gr. mod != = mod
142+
143+ # N.B.: This needs to match jl_maybe_add_binding_backedge
144+ function maybe_add_binding_backedge! (b:: Core.Binding , edge:: Union{Method, CodeInstance} )
145+ method = isa (edge, Method) ? edge : edge. def. def:: Method
146+ gr_needs_backedge_in_module (b. globalref, method. module) || return
147+ if ! isdefined (b, :backedges )
148+ b. backedges = Any[]
149+ end
150+ ! isempty (b. backedges) && b. backedges[end ] === edge && return
151+ push! (b. backedges, edge)
152+ end
153+
154+ function binding_was_invalidated (b:: Core.Binding )
155+ # At least one partition is required for invalidation
156+ ! isdefined (b, :partitions ) && return false
157+ b. partitions. min_world > unsafe_load (cglobal (:jl_require_world , UInt))
158+ end
159+
160+ function scan_new_method! (methods_with_invalidated_source:: IdSet{Method} , method:: Method )
161+ isdefined (method, :source ) || return
162+ src = _uncompressed_ir (method)
163+ mod = method. module
164+ foreachgr (src) do gr:: GlobalRef
165+ b = convert (Core. Binding, gr)
166+ binding_was_invalidated (b) && push! (methods_with_invalidated_source, method)
167+ maybe_add_binding_backedge! (b, method)
168+ end
169+ end
170+
171+ function scan_new_methods (extext_methods:: Vector{Any} , internal_methods:: Vector{Any} )
172+ methods_with_invalidated_source = IdSet {Method} ()
173+ for method in internal_methods
174+ if isa (method, Method)
175+ scan_new_method! (methods_with_invalidated_source, method)
176+ end
177+ end
178+ for tme:: Core.TypeMapEntry in extext_methods
179+ scan_new_method! (methods_with_invalidated_source, tme. func:: Method )
180+ end
181+ return methods_with_invalidated_source
182+ end
0 commit comments