Skip to content

Commit 1c26f43

Browse files
authored
better handling of missing backedges (#58636)
Manage a single dictionary (keyed by TypeName) instead of scattering this info into each TypeName scattered across the system. This makes it much easier to scan the whole table when required and to split it up better, so that all kwcalls and all constructors don't end up stuck into just one table. While not enormous (or even the largest) just using the REPL and Pkg, they are clearly larger than intended for a linear scan: ``` julia> length(Type.body.name.backedges) 1024 julia> length(typeof(Core.kwcall).name.backedges) 196 julia> length(typeof(convert).name.backedges) 1510 ```
1 parent d6b3669 commit 1c26f43

File tree

8 files changed

+257
-196
lines changed

8 files changed

+257
-196
lines changed

src/datatype.c

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -62,6 +62,7 @@ JL_DLLEXPORT jl_methtable_t *jl_new_method_table(jl_sym_t *name, jl_module_t *mo
6262
mt->cache = mc;
6363
mt->name = name;
6464
mt->module = module;
65+
mt->backedges = (jl_genericmemory_t*)jl_an_empty_memory_any;
6566
JL_GC_POP();
6667
return mt;
6768
}
@@ -88,7 +89,6 @@ JL_DLLEXPORT jl_typename_t *jl_new_typename_in(jl_sym_t *name, jl_module_t *modu
8889
tn->partial = NULL;
8990
tn->atomicfields = NULL;
9091
tn->constfields = NULL;
91-
tn->backedges = NULL;
9292
tn->max_methods = 0;
9393
jl_atomic_store_relaxed(&tn->max_args, 0);
9494
jl_atomic_store_relaxed(&tn->cache_entry_count, 0);

src/gf.c

Lines changed: 206 additions & 125 deletions
Large diffs are not rendered by default.

src/jltypes.c

Lines changed: 15 additions & 15 deletions
Original file line numberDiff line numberDiff line change
@@ -3004,23 +3004,22 @@ void jl_init_types(void) JL_GC_DISABLED
30043004
jl_typename_type->name->wrapper = (jl_value_t*)jl_typename_type;
30053005
jl_typename_type->super = jl_any_type;
30063006
jl_typename_type->parameters = jl_emptysvec;
3007-
jl_typename_type->name->n_uninitialized = 19 - 2;
3008-
jl_typename_type->name->names = jl_perm_symsvec(19, "name", "module", "singletonname",
3007+
jl_typename_type->name->n_uninitialized = 18 - 2;
3008+
jl_typename_type->name->names = jl_perm_symsvec(18, "name", "module", "singletonname",
30093009
"names", "atomicfields", "constfields",
30103010
"wrapper", "Typeofwrapper", "cache", "linearcache",
3011-
"backedges", "partial",
3012-
"hash", "max_args", "n_uninitialized",
3011+
"partial", "hash", "max_args", "n_uninitialized",
30133012
"flags", // "abstract", "mutable", "mayinlinealloc",
30143013
"cache_entry_count", "max_methods", "constprop_heuristic");
3015-
const static uint32_t typename_constfields[1] = { 0b0001101000001001011 }; // TODO: put back atomicfields and constfields in this list
3016-
const static uint32_t typename_atomicfields[1] = { 0b0010010001110000000 };
3014+
const static uint32_t typename_constfields[1] = { 0b000110100001001011 }; // TODO: put back atomicfields and constfields in this list
3015+
const static uint32_t typename_atomicfields[1] = { 0b001001001110000000 };
30173016
jl_typename_type->name->constfields = typename_constfields;
30183017
jl_typename_type->name->atomicfields = typename_atomicfields;
30193018
jl_precompute_memoized_dt(jl_typename_type, 1);
3020-
jl_typename_type->types = jl_svec(19, jl_symbol_type, jl_any_type /*jl_module_type*/, jl_symbol_type,
3019+
jl_typename_type->types = jl_svec(18, jl_symbol_type, jl_any_type /*jl_module_type*/, jl_symbol_type,
30213020
jl_simplevector_type,
30223021
jl_any_type/*jl_voidpointer_type*/, jl_any_type/*jl_voidpointer_type*/,
3023-
jl_type_type, jl_type_type, jl_simplevector_type, jl_simplevector_type,
3022+
jl_type_type, jl_simplevector_type, jl_simplevector_type,
30243023
jl_methcache_type, jl_any_type,
30253024
jl_any_type /*jl_long_type*/,
30263025
jl_any_type /*jl_int32_type*/,
@@ -3046,13 +3045,13 @@ void jl_init_types(void) JL_GC_DISABLED
30463045
jl_methtable_type->super = jl_any_type;
30473046
jl_methtable_type->parameters = jl_emptysvec;
30483047
jl_methtable_type->name->n_uninitialized = 0;
3049-
jl_methtable_type->name->names = jl_perm_symsvec(4, "defs", "cache", "name", "module");
3050-
const static uint32_t methtable_constfields[1] = { 0b1110 };
3051-
const static uint32_t methtable_atomicfields[1] = { 0b0001 };
3048+
jl_methtable_type->name->names = jl_perm_symsvec(5, "defs", "cache", "name", "module", "backedges");
3049+
const static uint32_t methtable_constfields[1] = { 0b01110 };
3050+
const static uint32_t methtable_atomicfields[1] = { 0b00001 };
30523051
jl_methtable_type->name->constfields = methtable_constfields;
30533052
jl_methtable_type->name->atomicfields = methtable_atomicfields;
30543053
jl_precompute_memoized_dt(jl_methtable_type, 1);
3055-
jl_methtable_type->types = jl_svec(4, jl_any_type, jl_methcache_type, jl_symbol_type, jl_any_type /*jl_module_type*/);
3054+
jl_methtable_type->types = jl_svec(5, jl_any_type, jl_methcache_type, jl_symbol_type, jl_any_type /*jl_module_type*/, jl_any_type);
30563055

30573056
jl_symbol_type->name = jl_new_typename_in(jl_symbol("Symbol"), core, 0, 1);
30583057
jl_symbol_type->name->wrapper = (jl_value_t*)jl_symbol_type;
@@ -3378,6 +3377,7 @@ void jl_init_types(void) JL_GC_DISABLED
33783377
core = jl_core_module;
33793378
jl_method_table->module = core;
33803379
jl_atomic_store_relaxed(&jl_method_table->cache->leafcache, (jl_genericmemory_t*)jl_an_empty_memory_any);
3380+
jl_method_table->backedges = (jl_genericmemory_t*)jl_an_empty_memory_any;
33813381
jl_atomic_store_relaxed(&core->bindingkeyset, (jl_genericmemory_t*)jl_an_empty_memory_any);
33823382
// export own name, so "using Foo" makes "Foo" itself visible
33833383
jl_set_initial_const(core, core->name, (jl_value_t*)core, 1);
@@ -3842,13 +3842,13 @@ void jl_init_types(void) JL_GC_DISABLED
38423842
jl_svecset(jl_typename_type->types, 5, jl_voidpointer_type);
38433843
jl_svecset(jl_typename_type->types, 6, jl_type_type);
38443844
jl_svecset(jl_typename_type->types, 7, jl_type_type);
3845-
jl_svecset(jl_typename_type->types, 12, jl_long_type);
3845+
jl_svecset(jl_typename_type->types, 11, jl_long_type);
3846+
jl_svecset(jl_typename_type->types, 12, jl_int32_type);
38463847
jl_svecset(jl_typename_type->types, 13, jl_int32_type);
3847-
jl_svecset(jl_typename_type->types, 14, jl_int32_type);
3848+
jl_svecset(jl_typename_type->types, 14, jl_uint8_type);
38483849
jl_svecset(jl_typename_type->types, 15, jl_uint8_type);
38493850
jl_svecset(jl_typename_type->types, 16, jl_uint8_type);
38503851
jl_svecset(jl_typename_type->types, 17, jl_uint8_type);
3851-
jl_svecset(jl_typename_type->types, 18, jl_uint8_type);
38523852
jl_svecset(jl_methcache_type->types, 2, jl_long_type); // voidpointer
38533853
jl_svecset(jl_methcache_type->types, 3, jl_long_type); // uint32_t plus alignment
38543854
jl_svecset(jl_methtable_type->types, 3, jl_module_type);

src/julia.h

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -520,7 +520,6 @@ typedef struct {
520520
_Atomic(jl_value_t*) Typeofwrapper; // cache for Type{wrapper}
521521
_Atomic(jl_svec_t*) cache; // sorted array
522522
_Atomic(jl_svec_t*) linearcache; // unsorted array
523-
jl_array_t *backedges; // uncovered (sig => caller::CodeInstance) pairs with this type as the function
524523
jl_array_t *partial; // incomplete instantiations of this type
525524
intptr_t hash;
526525
_Atomic(int32_t) max_args; // max # of non-vararg arguments in a signature with this type as the function
@@ -882,6 +881,7 @@ typedef struct _jl_methtable_t {
882881
jl_methcache_t *cache;
883882
jl_sym_t *name; // sometimes used for debug printing
884883
jl_module_t *module; // sometimes used for debug printing
884+
jl_genericmemory_t *backedges; // IdDict{top typenames, Vector{uncovered (sig => caller::CodeInstance)}}
885885
} jl_methtable_t;
886886

887887
typedef struct {

src/julia_internal.h

Lines changed: 0 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -857,7 +857,6 @@ jl_expr_t *jl_exprn(jl_sym_t *head, size_t n);
857857
jl_function_t *jl_new_generic_function(jl_sym_t *name, jl_module_t *module, size_t new_world);
858858
jl_function_t *jl_new_generic_function_with_supertype(jl_sym_t *name, jl_module_t *module, jl_datatype_t *st, size_t new_world);
859859
int jl_foreach_reachable_mtable(int (*visit)(jl_methtable_t *mt, void *env), jl_array_t *mod_array, void *env);
860-
int foreach_mtable_in_module(jl_module_t *m, int (*visit)(jl_methtable_t *mt, void *env), void *env);
861860
void jl_init_main_module(void);
862861
JL_DLLEXPORT int jl_is_submodule(jl_module_t *child, jl_module_t *parent) JL_NOTSAFEPOINT;
863862
jl_array_t *jl_get_loaded_modules(void);
@@ -939,7 +938,6 @@ JL_DLLEXPORT jl_methtable_t *jl_method_get_table(
939938
jl_method_t *method JL_PROPAGATES_ROOT) JL_NOTSAFEPOINT;
940939
JL_DLLEXPORT jl_methcache_t *jl_method_get_cache(
941940
jl_method_t *method JL_PROPAGATES_ROOT) JL_NOTSAFEPOINT;
942-
void jl_foreach_top_typename_for(void (*f)(jl_typename_t*, void*), jl_value_t *argtypes JL_PROPAGATES_ROOT, void *env);
943941

944942
JL_DLLEXPORT int jl_pointer_egal(jl_value_t *t);
945943
JL_DLLEXPORT jl_value_t *jl_nth_slot_type(jl_value_t *sig JL_PROPAGATES_ROOT, size_t i) JL_NOTSAFEPOINT;

src/method.c

Lines changed: 0 additions & 38 deletions
Original file line numberDiff line numberDiff line change
@@ -1154,39 +1154,6 @@ JL_DLLEXPORT jl_value_t *jl_declare_const_gf(jl_module_t *mod, jl_sym_t *name)
11541154
return gf;
11551155
}
11561156

1157-
static void foreach_top_nth_typename(void (*f)(jl_typename_t*, void*), jl_value_t *a JL_PROPAGATES_ROOT, int n, void *env)
1158-
{
1159-
if (jl_is_datatype(a)) {
1160-
if (n == 0) {
1161-
jl_datatype_t *dt = ((jl_datatype_t*)a);
1162-
jl_typename_t *tn = NULL;
1163-
while (1) {
1164-
if (dt != jl_any_type && dt != jl_function_type)
1165-
tn = dt->name;
1166-
if (dt->super == dt)
1167-
break;
1168-
dt = dt->super;
1169-
}
1170-
if (tn)
1171-
f(tn, env);
1172-
}
1173-
else if (jl_is_tuple_type(a)) {
1174-
if (jl_nparams(a) >= n)
1175-
foreach_top_nth_typename(f, jl_tparam(a, n - 1), 0, env);
1176-
}
1177-
}
1178-
else if (jl_is_typevar(a)) {
1179-
foreach_top_nth_typename(f, ((jl_tvar_t*)a)->ub, n, env);
1180-
}
1181-
else if (jl_is_unionall(a)) {
1182-
foreach_top_nth_typename(f, ((jl_unionall_t*)a)->body, n, env);
1183-
}
1184-
else if (jl_is_uniontype(a)) {
1185-
jl_uniontype_t *u = (jl_uniontype_t*)a;
1186-
foreach_top_nth_typename(f, u->a, n, env);
1187-
foreach_top_nth_typename(f, u->b, n, env);
1188-
}
1189-
}
11901157

11911158
// get the MethodTable for dispatch, or `nothing` if cannot be determined
11921159
JL_DLLEXPORT jl_methtable_t *jl_method_table_for(jl_value_t *argtypes JL_PROPAGATES_ROOT) JL_NOTSAFEPOINT
@@ -1200,11 +1167,6 @@ JL_DLLEXPORT jl_methcache_t *jl_method_cache_for(jl_value_t *argtypes JL_PROPAGA
12001167
return jl_method_table->cache;
12011168
}
12021169

1203-
void jl_foreach_top_typename_for(void (*f)(jl_typename_t*, void*), jl_value_t *argtypes JL_PROPAGATES_ROOT, void *env)
1204-
{
1205-
foreach_top_nth_typename(f, argtypes, 1, env);
1206-
}
1207-
12081170
jl_methcache_t *jl_kwmethod_cache_for(jl_value_t *argtypes JL_PROPAGATES_ROOT) JL_NOTSAFEPOINT
12091171
{
12101172
return jl_method_table->cache;

src/staticdata.c

Lines changed: 32 additions & 12 deletions
Original file line numberDiff line numberDiff line change
@@ -867,20 +867,30 @@ static void jl_insert_into_serialization_queue(jl_serializer_state *s, jl_value_
867867
assert(!jl_object_in_image((jl_value_t*)tn->module));
868868
assert(!jl_object_in_image((jl_value_t*)tn->wrapper));
869869
}
870+
}
871+
if (jl_is_mtable(v)) {
872+
jl_methtable_t *mt = (jl_methtable_t*)v;
870873
// Any back-edges will be re-validated and added by staticdata.jl, so
871874
// drop them from the image here
872875
if (s->incremental || jl_options.trim || jl_options.strip_ir) {
873-
record_field_change((jl_value_t**)&tn->backedges, NULL);
876+
record_field_change((jl_value_t**)&mt->backedges, jl_an_empty_memory_any);
874877
}
875878
else {
876879
// don't recurse into all backedges memory (yet)
877-
jl_value_t *backedges = get_replaceable_field((jl_value_t**)&tn->backedges, 1);
878-
if (backedges) {
879-
jl_queue_for_serialization_(s, (jl_value_t*)((jl_array_t*)backedges)->ref.mem, 0, 1);
880-
for (size_t i = 0, n = jl_array_nrows(backedges); i < n; i += 2) {
881-
jl_value_t *t = jl_array_ptr_ref(backedges, i);
882-
assert(!jl_is_code_instance(t));
883-
jl_queue_for_serialization(s, t);
880+
jl_value_t *allbackedges = get_replaceable_field((jl_value_t**)&mt->backedges, 1);
881+
jl_queue_for_serialization_(s, allbackedges, 0, 1);
882+
for (size_t i = 0, n = ((jl_genericmemory_t*)allbackedges)->length; i < n; i += 2) {
883+
jl_value_t *tn = jl_genericmemory_ptr_ref(allbackedges, i);
884+
jl_queue_for_serialization(s, tn);
885+
jl_value_t *backedges = jl_genericmemory_ptr_ref(allbackedges, i + 1);
886+
if (backedges && backedges != jl_nothing) {
887+
jl_queue_for_serialization_(s, (jl_value_t*)((jl_array_t*)backedges)->ref.mem, 0, 1);
888+
jl_queue_for_serialization(s, backedges);
889+
for (size_t i = 0, n = jl_array_nrows(backedges); i < n; i += 2) {
890+
jl_value_t *t = jl_array_ptr_ref(backedges, i);
891+
assert(!jl_is_code_instance(t));
892+
jl_queue_for_serialization(s, t);
893+
}
884894
}
885895
}
886896
}
@@ -2573,8 +2583,6 @@ static void jl_prune_mi_backedges(jl_array_t *backedges)
25732583

25742584
static void jl_prune_tn_backedges(jl_array_t *backedges)
25752585
{
2576-
if (backedges == NULL)
2577-
return;
25782586
size_t i = 0, ins = 0, n = jl_array_nrows(backedges);
25792587
for (i = 1; i < n; i += 2) {
25802588
jl_value_t *ci = jl_array_ptr_ref(backedges, i);
@@ -2586,6 +2594,15 @@ static void jl_prune_tn_backedges(jl_array_t *backedges)
25862594
jl_array_del_end(backedges, n - ins);
25872595
}
25882596

2597+
static void jl_prune_mt_backedges(jl_genericmemory_t *allbackedges)
2598+
{
2599+
for (size_t i = 0, n = allbackedges->length; i < n; i += 2) {
2600+
jl_value_t *tn = jl_genericmemory_ptr_ref(allbackedges, i);
2601+
jl_value_t *backedges = jl_genericmemory_ptr_ref(allbackedges, i + 1);
2602+
if (tn && tn != jl_nothing && backedges)
2603+
jl_prune_tn_backedges((jl_array_t*)backedges);
2604+
}
2605+
}
25892606

25902607
static void jl_prune_binding_backedges(jl_array_t *backedges)
25912608
{
@@ -3240,8 +3257,6 @@ static void jl_save_system_image_to_stream(ios_t *f, jl_array_t *mod_array,
32403257
jl_prune_type_cache_hash(jl_atomic_load_relaxed(&tn->cache)));
32413258
jl_gc_wb(tn, jl_atomic_load_relaxed(&tn->cache));
32423259
jl_prune_type_cache_linear(jl_atomic_load_relaxed(&tn->linearcache));
3243-
jl_value_t *backedges = get_replaceable_field((jl_value_t**)&tn->backedges, 1);
3244-
jl_prune_tn_backedges((jl_array_t*)backedges);
32453260
}
32463261
else if (jl_is_method_instance(v)) {
32473262
jl_method_instance_t *mi = (jl_method_instance_t*)v;
@@ -3253,6 +3268,11 @@ static void jl_save_system_image_to_stream(ios_t *f, jl_array_t *mod_array,
32533268
jl_value_t *backedges = get_replaceable_field((jl_value_t**)&b->backedges, 1);
32543269
jl_prune_binding_backedges((jl_array_t*)backedges);
32553270
}
3271+
else if (jl_is_mtable(v)) {
3272+
jl_methtable_t *mt = (jl_methtable_t*)v;
3273+
jl_value_t *backedges = get_replaceable_field((jl_value_t**)&mt->backedges, 1);
3274+
jl_prune_mt_backedges((jl_genericmemory_t*)backedges);
3275+
}
32563276
}
32573277
}
32583278

test/misc.jl

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1632,10 +1632,10 @@ end
16321632
let errs = IOBuffer()
16331633
run(`$(Base.julia_cmd()) -e '
16341634
using Test
1635-
@test isdefined(Type.body.name, :backedges)
1635+
@test !isempty(Core.GlobalMethods.backedges)
16361636
Base.Experimental.disable_new_worlds()
16371637
@test_throws "disable_new_worlds" @eval f() = 1
1638-
@test !isdefined(Type.body.name, :backedges)
1638+
@test isempty(Core.GlobalMethods.backedges)
16391639
@test_throws "disable_new_worlds" Base.delete_method(which(+, (Int, Int)))
16401640
@test 1+1 == 2
16411641
using Dates

0 commit comments

Comments
 (0)