|
8 | 8 | . static parameter inference |
9 | 9 | . method specialization and caching, invoking type inference |
10 | 10 | */ |
| 11 | +#include <stdbool.h> |
11 | 12 | #include <stdlib.h> |
12 | 13 | #include <string.h> |
13 | 14 | #include "julia.h" |
|
24 | 25 | extern "C" { |
25 | 26 | #endif |
26 | 27 |
|
| 28 | +static _Atomic(bool) allow_new_worlds = true; |
27 | 29 | JL_DLLEXPORT _Atomic(size_t) jl_world_counter = 1; // uses atomic acquire/release |
28 | 30 | JL_DLLEXPORT size_t jl_get_world_counter(void) JL_NOTSAFEPOINT |
29 | 31 | { |
@@ -1718,6 +1720,8 @@ static void invalidate_backedges(void (*f)(jl_code_instance_t*), jl_method_insta |
1718 | 1720 | // add a backedge from callee to caller |
1719 | 1721 | JL_DLLEXPORT void jl_method_instance_add_backedge(jl_method_instance_t *callee, jl_value_t *invokesig, jl_method_instance_t *caller) |
1720 | 1722 | { |
| 1723 | + if (!jl_atomic_load_acquire(&allow_new_worlds)) |
| 1724 | + return; |
1721 | 1725 | JL_LOCK(&callee->def.method->writelock); |
1722 | 1726 | if (invokesig == jl_nothing) |
1723 | 1727 | 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, |
1753 | 1757 | // add a backedge from a non-existent signature to caller |
1754 | 1758 | JL_DLLEXPORT void jl_method_table_add_backedge(jl_methtable_t *mt, jl_value_t *typ, jl_value_t *caller) |
1755 | 1759 | { |
| 1760 | + if (!jl_atomic_load_acquire(&allow_new_worlds)) |
| 1761 | + return; |
1756 | 1762 | JL_LOCK(&mt->writelock); |
1757 | 1763 | if (!mt->backedges) { |
1758 | 1764 | // lazy-init the backedges array |
@@ -1915,8 +1921,48 @@ static void jl_method_table_invalidate(jl_methtable_t *mt, jl_typemap_entry_t *m |
1915 | 1921 | } |
1916 | 1922 | } |
1917 | 1923 |
|
| 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 | + |
1918 | 1962 | JL_DLLEXPORT void jl_method_table_disable(jl_methtable_t *mt, jl_method_t *method) |
1919 | 1963 | { |
| 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."); |
1920 | 1966 | jl_typemap_entry_t *methodentry = do_typemap_search(mt, method); |
1921 | 1967 | JL_LOCK(&mt->writelock); |
1922 | 1968 | // 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_ |
1986 | 2032 |
|
1987 | 2033 | JL_DLLEXPORT void jl_method_table_insert(jl_methtable_t *mt, jl_method_t *method, jl_tupletype_t *simpletype) |
1988 | 2034 | { |
| 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."); |
1989 | 2037 | JL_TIMING(ADD_METHOD, ADD_METHOD); |
1990 | 2038 | assert(jl_is_method(method)); |
1991 | 2039 | assert(jl_is_mtable(mt)); |
|
0 commit comments