Skip to content

Conversation

@Keno
Copy link
Member

@Keno Keno commented Jan 31, 2025

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 Add edge kind for access to non-explicit partitioned bindings #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.

Base automatically changed from kf/missingbackedges to master January 31, 2025 14:36
@Keno Keno force-pushed the kf/bindingbackedges branch from 00c949f to c7006ec Compare February 1, 2025 07:18
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.
@Keno Keno force-pushed the kf/bindingbackedges branch from c7006ec to d85c37a Compare February 2, 2025 01:55
@Keno Keno merged commit e485be8 into master Feb 2, 2025
7 checks passed
@Keno Keno deleted the kf/bindingbackedges branch February 2, 2025 07:23

function should_invalidate_code_for_globalref(gr::GlobalRef, src::CodeInfo)
isgr(g::GlobalRef) = gr.mod == g.mod && gr.name === g.name
isgr(g) = false
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

@nospecialize?

Comment on lines +125 to +126
if isdefined(b, :backedges)
for edge in b.backedges
Copy link
Member

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"),
Copy link
Member

@vtjnash vtjnash Feb 3, 2025

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)

Comment on lines +1120 to +1121
} else if (jl_array_len(b->backedges) > 0 &&
jl_array_ptr_ref(b->backedges, jl_array_len(b->backedges)-1) == edge) {
Copy link
Member

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)?

@nsajko nsajko mentioned this pull request Mar 7, 2025
serenity4 pushed a commit to serenity4/julia that referenced this pull request May 1, 2025
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.
vtjnash added a commit that referenced this pull request May 29, 2025
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
KristofferC pushed a commit that referenced this pull request Jun 2, 2025
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)
vtjnash added a commit that referenced this pull request Jun 5, 2025
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)
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

2 participants