Skip to content

Commit 918a99d

Browse files
authored
Optionally disallow defining new methods and drop backedges (#198)
* Optionally disallow defining new methods and drop backedges
1 parent 5610223 commit 918a99d

File tree

2 files changed

+50
-2
lines changed

2 files changed

+50
-2
lines changed

src/gf.c

Lines changed: 48 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -8,6 +8,7 @@
88
. static parameter inference
99
. method specialization and caching, invoking type inference
1010
*/
11+
#include <stdbool.h>
1112
#include <stdlib.h>
1213
#include <string.h>
1314
#include "julia.h"
@@ -24,6 +25,7 @@
2425
extern "C" {
2526
#endif
2627

28+
static _Atomic(bool) allow_new_worlds = true;
2729
JL_DLLEXPORT _Atomic(size_t) jl_world_counter = 1; // uses atomic acquire/release
2830
JL_DLLEXPORT size_t jl_get_world_counter(void) JL_NOTSAFEPOINT
2931
{
@@ -1718,6 +1720,8 @@ static void invalidate_backedges(void (*f)(jl_code_instance_t*), jl_method_insta
17181720
// add a backedge from callee to caller
17191721
JL_DLLEXPORT void jl_method_instance_add_backedge(jl_method_instance_t *callee, jl_value_t *invokesig, jl_method_instance_t *caller)
17201722
{
1723+
if (!jl_atomic_load_acquire(&allow_new_worlds))
1724+
return;
17211725
JL_LOCK(&callee->def.method->writelock);
17221726
if (invokesig == jl_nothing)
17231727
invokesig = NULL; // julia uses `nothing` but C uses NULL (#undef)
@@ -1753,6 +1757,8 @@ JL_DLLEXPORT void jl_method_instance_add_backedge(jl_method_instance_t *callee,
17531757
// add a backedge from a non-existent signature to caller
17541758
JL_DLLEXPORT void jl_method_table_add_backedge(jl_methtable_t *mt, jl_value_t *typ, jl_value_t *caller)
17551759
{
1760+
if (!jl_atomic_load_acquire(&allow_new_worlds))
1761+
return;
17561762
JL_LOCK(&mt->writelock);
17571763
if (!mt->backedges) {
17581764
// lazy-init the backedges array
@@ -1915,8 +1921,48 @@ static void jl_method_table_invalidate(jl_methtable_t *mt, jl_typemap_entry_t *m
19151921
}
19161922
}
19171923

1924+
static int erase_method_backedges(jl_typemap_entry_t *def, void *closure)
1925+
{
1926+
jl_method_t *method = def->func.method;
1927+
jl_value_t *specializations = jl_atomic_load_relaxed(&method->specializations);
1928+
if (jl_is_svec(specializations)) {
1929+
size_t i, l = jl_svec_len(specializations);
1930+
for (i = 0; i < l; i++) {
1931+
jl_method_instance_t *mi = (jl_method_instance_t*)jl_svecref(specializations, i);
1932+
if ((jl_value_t*)mi != jl_nothing) {
1933+
mi->backedges = NULL;
1934+
}
1935+
}
1936+
}
1937+
else {
1938+
jl_method_instance_t *mi = (jl_method_instance_t*)specializations;
1939+
mi->backedges = NULL;
1940+
}
1941+
return 1;
1942+
}
1943+
1944+
static int erase_all_backedges(jl_methtable_t *mt, void *env)
1945+
{
1946+
// removes all method caches
1947+
// this might not be entirely safe (GC or MT), thus we only do it very early in bootstrapping
1948+
mt->backedges = NULL;
1949+
jl_typemap_visitor(jl_atomic_load_relaxed(&mt->defs), erase_method_backedges, env);
1950+
return 1;
1951+
}
1952+
1953+
JL_DLLEXPORT void jl_disable_new_worlds(void)
1954+
{
1955+
if (jl_generating_output())
1956+
jl_error("Disabling Method changes is not possible when generating output.");
1957+
jl_atomic_store_release(&allow_new_worlds, false);
1958+
jl_foreach_reachable_mtable(erase_all_backedges, (void*)NULL);
1959+
}
1960+
1961+
19181962
JL_DLLEXPORT void jl_method_table_disable(jl_methtable_t *mt, jl_method_t *method)
19191963
{
1964+
if (!jl_atomic_load_acquire(&allow_new_worlds))
1965+
jl_error("Method changes have been disabled via a call to jl_disable_new_worlds.");
19201966
jl_typemap_entry_t *methodentry = do_typemap_search(mt, method);
19211967
JL_LOCK(&mt->writelock);
19221968
// Narrow the world age on the method to make it uncallable
@@ -1986,6 +2032,8 @@ static int is_replacing(char ambig, jl_value_t *type, jl_method_t *m, jl_method_
19862032

19872033
JL_DLLEXPORT void jl_method_table_insert(jl_methtable_t *mt, jl_method_t *method, jl_tupletype_t *simpletype)
19882034
{
2035+
if (!jl_atomic_load_acquire(&allow_new_worlds))
2036+
jl_error("Method changes have been disabled via a call to jl_disable_new_worlds.");
19892037
JL_TIMING(ADD_METHOD, ADD_METHOD);
19902038
assert(jl_is_method(method));
19912039
assert(jl_is_mtable(mt));

src/staticdata.c

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -3447,11 +3447,11 @@ static jl_value_t *jl_restore_package_image_from_stream(void* pkgimage_handle, i
34473447
jl_restore_system_image_from_stream_(f, image, depmods, checksum, (jl_array_t**)&restored, &init_order, &extext_methods, &new_specializations, &method_roots_list, &ext_targets, &edges, &base, &ccallable_list, &cachesizes);
34483448
JL_SIGATOMIC_END();
34493449

3450-
// Insert method extensions
3451-
jl_insert_methods(extext_methods);
34523450
// No special processing of `new_specializations` is required because recaching handled it
34533451
// Add roots to methods
34543452
jl_copy_roots(method_roots_list, jl_worklist_key((jl_array_t*)restored));
3453+
// Insert method extensions
3454+
jl_insert_methods(extext_methods);
34553455
// Handle edges
34563456
size_t world = jl_atomic_load_acquire(&jl_world_counter);
34573457
jl_insert_backedges((jl_array_t*)edges, (jl_array_t*)ext_targets, (jl_array_t*)new_specializations, world); // restore external backedges (needs to be last)

0 commit comments

Comments
 (0)