-
-
Notifications
You must be signed in to change notification settings - Fork 5.7k
bpart: Start tracking backedges for bindings #57213
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Conversation
00c949f to
c7006ec
Compare
This PR adds limited backedge support for Bindings. There are two classes of bindings that get backedges: 1. Cross-module `GlobalRef` bindings (new in this PR) 2. Any globals accesses through intrinsics (i.e. those with forward edges from #57009) This is a time/space trade-off for invalidation. As a result of the first category, invalidating a binding now only needs to scan all the methods defined in the same module as the binding. At the same time, it is anticipated that most binding references are to bindings in the same module, keeping the list of bindings that need explicit (back)edges small.
c7006ec to
d85c37a
Compare
|
|
||
| function should_invalidate_code_for_globalref(gr::GlobalRef, src::CodeInfo) | ||
| isgr(g::GlobalRef) = gr.mod == g.mod && gr.name === g.name | ||
| isgr(g) = false |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
@nospecialize?
| if isdefined(b, :backedges) | ||
| for edge in b.backedges |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
This appears to trigger UB when julia runs with threads (the default) and does any inference, since b.backedges is accessed without a lock here
| jl_new_datatype(jl_symbol("Binding"), core, jl_any_type, jl_emptysvec, | ||
| jl_perm_symsvec(4, "globalref", "value", "partitions", "flags"), | ||
| jl_svec(4, jl_any_type/*jl_globalref_type*/, jl_any_type, jl_binding_partition_type, jl_uint8_type), | ||
| jl_perm_symsvec(5, "globalref", "value", "partitions", "backedges", "flags"), |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Any idea of the rough cost of this? I wondered if we should combine them more (e.g. put this backedge list on the containing Module instead, so that any mutation of a Binding in the Module has to scan though all edges to any Bindings used outside that Module). Depends really on how costly this level of tracking detail seems though. (and because then we have the obvious module->write_lock we can use to fix up some of the data race UB here–though we can probably use that lock anyways)
| } else if (jl_array_len(b->backedges) > 0 && | ||
| jl_array_ptr_ref(b->backedges, jl_array_len(b->backedges)-1) == edge) { |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
IIUC, this should be scanning the whole list, not just checking the last one (particularly because of the thread-safety issues this currently incurs)?
This PR adds limited backedge support for Bindings. There are two classes of bindings that get backedges: 1. Cross-module `GlobalRef` bindings (new in this PR) 2. Any globals accesses through intrinsics (i.e. those with forward edges from JuliaLang#57009) This is a time/space trade-off for invalidation. As a result of the first category, invalidating a binding now only needs to scan all the methods defined in the same module as the binding. At the same time, it is anticipated that most binding references are to bindings in the same module, keeping the list of bindings that need explicit (back)edges small.
Introduce a new `jl_get_global_value` to do the new world-aware behavior, while preserving the old behavior for `jl_get_global`. Choose between `jl_get_global`, `jl_get_global_value`, and `jl_eval_global_var`, depending on what behavior is required. Also take this opportunity to fix some data race mistakes introduced by bindings (relaxed loads of jl_world_counter outside of assert) and lacking type asserts / unnecessary globals in precompile code. Fix #58097 Addresses post-review comment #57213 (comment), so this is already tested against by existing logic
Introduce a new `jl_get_global_value` to do the new world-aware behavior, while preserving the old behavior for `jl_get_global`. Choose between `jl_get_global`, `jl_get_global_value`, and `jl_eval_global_var`, depending on what behavior is required. Also take this opportunity to fix some data race mistakes introduced by bindings (relaxed loads of jl_world_counter outside of assert) and lacking type asserts / unnecessary globals in precompile code. Fix #58097 Addresses post-review comment #57213 (comment), so this is already tested against by existing logic (cherry picked from commit 965d007)
Introduce a new `jl_get_global_value` to do the new world-aware behavior, while preserving the old behavior for `jl_get_global`. Choose between `jl_get_global`, `jl_get_global_value`, and `jl_eval_global_var`, depending on what behavior is required. Also take this opportunity to fix some data race mistakes introduced by bindings (relaxed loads of jl_world_counter outside of assert) and lacking type asserts / unnecessary globals in precompile code. Fix #58097 Addresses post-review comment #57213 (comment), so this is already tested against by existing logic (cherry picked from commit 965d007)
This PR adds limited backedge support for Bindings. There are two classes of bindings that get backedges:
GlobalRefbindings (new in this PR)This is a time/space trade-off for invalidation. As a result of the first category, invalidating a binding now only needs to scan all the methods defined in the same module as the binding. At the same time, it is anticipated that most binding references are to bindings in the same module, keeping the list of bindings that need explicit (back)edges small.