Skip to content

Commit 09b632d

Browse files
committed
Add basic code for binding partition revalidation
This adds the binding partition revalidation code from #54654. This is the last piece of that PR that hasn't been merged yet - however the TODO in that PR still stands for future work. This PR itself adds a callback that gets triggered by deleting a binding. It will then walk all code in the system and invalidate code instances of Methods whose lowered source referenced the given global. This walk is quite slow. Future work will add backedges and optimizations to make this faster, but the basic functionality should be in place with this PR.
1 parent e624440 commit 09b632d

File tree

4 files changed

+42
-2
lines changed

4 files changed

+42
-2
lines changed

base/Base_compiler.jl

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -253,6 +253,7 @@ include("ordering.jl")
253253
using .Order
254254

255255
include("coreir.jl")
256+
include("invalidation.jl")
256257

257258
# For OS specific stuff
258259
# We need to strcat things here, before strings are really defined

src/gf.c

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1784,6 +1784,11 @@ static void invalidate_code_instance(jl_code_instance_t *replaced, size_t max_wo
17841784
JL_UNLOCK(&replaced->def->def.method->writelock);
17851785
}
17861786

1787+
JL_DLLEXPORT void jl_invalidate_code_instance(jl_code_instance_t *replaced, size_t max_world)
1788+
{
1789+
invalidate_code_instance(replaced, max_world, 1);
1790+
}
1791+
17871792
static void _invalidate_backedges(jl_method_instance_t *replaced_mi, size_t max_world, int depth) {
17881793
jl_array_t *backedges = replaced_mi->backedges;
17891794
if (backedges) {

src/module.c

Lines changed: 29 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1025,6 +1025,21 @@ JL_DLLEXPORT void jl_set_const(jl_module_t *m JL_ROOTING_ARGUMENT, jl_sym_t *var
10251025
jl_gc_wb(bpart, val);
10261026
}
10271027

1028+
void jl_invalidate_binding_refs(jl_globalref_t *ref, size_t new_world)
1029+
{
1030+
static jl_value_t *invalidate_code_for_globalref = NULL;
1031+
if (invalidate_code_for_globalref == NULL && jl_base_module != NULL)
1032+
invalidate_code_for_globalref = jl_get_global(jl_base_module, jl_symbol("invalidate_code_for_globalref!"));
1033+
if (!invalidate_code_for_globalref)
1034+
jl_error("Binding invalidation is not permitted during bootstrap.");
1035+
if (jl_generating_output())
1036+
jl_error("Binding invalidation is not permitted during image generation.");
1037+
jl_value_t *boxed_world = jl_box_ulong(new_world);
1038+
JL_GC_PUSH1(&boxed_world);
1039+
jl_call2((jl_function_t*)invalidate_code_for_globalref, (jl_value_t*)ref, boxed_world);
1040+
JL_GC_POP();
1041+
}
1042+
10281043
extern jl_mutex_t world_counter_lock;
10291044
JL_DLLEXPORT void jl_disable_binding(jl_globalref_t *gr)
10301045
{
@@ -1039,9 +1054,16 @@ JL_DLLEXPORT void jl_disable_binding(jl_globalref_t *gr)
10391054

10401055
JL_LOCK(&world_counter_lock);
10411056
jl_task_t *ct = jl_current_task;
1057+
size_t last_world = ct->world_age;
10421058
size_t new_max_world = jl_atomic_load_acquire(&jl_world_counter);
1043-
// TODO: Trigger invalidation here
1044-
(void)ct;
1059+
JL_TRY {
1060+
ct->world_age = jl_typeinf_world;
1061+
jl_invalidate_binding_refs(gr, new_max_world);
1062+
} JL_CATCH {
1063+
JL_UNLOCK(&world_counter_lock);
1064+
jl_rethrow();
1065+
}
1066+
ct->world_age = last_world;
10451067
jl_atomic_store_release(&bpart->max_world, new_max_world);
10461068
jl_atomic_store_release(&jl_world_counter, new_max_world + 1);
10471069
JL_UNLOCK(&world_counter_lock);
@@ -1327,6 +1349,11 @@ JL_DLLEXPORT void jl_add_to_module_init_list(jl_value_t *mod)
13271349
jl_array_ptr_1d_push(jl_module_init_order, mod);
13281350
}
13291351

1352+
JL_DLLEXPORT jl_svec_t *jl_module_get_bindings(jl_module_t *m)
1353+
{
1354+
return jl_atomic_load_relaxed(&m->bindings);
1355+
}
1356+
13301357
JL_DLLEXPORT void jl_init_restored_module(jl_value_t *mod)
13311358
{
13321359
if (!jl_generating_output() || jl_options.incremental) {

test/rebinding.jl

Lines changed: 7 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -33,4 +33,11 @@ module Rebinding
3333
@test Base.@world(Foo, defined_world_age) == typeof(x)
3434
@test Base.@world(Rebinding.Foo, defined_world_age) == typeof(x)
3535
@test Base.@world((@__MODULE__).Foo, defined_world_age) == typeof(x)
36+
37+
# Test invalidation (const -> undefined)
38+
const delete_me = 1
39+
f_return_delete_me() = delete_me
40+
@test f_return_delete_me() == 1
41+
Base.delete_binding(@__MODULE__, :delete_me)
42+
@test_throws UndefVarError f_return_delete_me()
3643
end

0 commit comments

Comments
 (0)