Skip to content

Commit d87f8f9

Browse files
vtjnashKristofferC
authored andcommitted
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 ``` (cherry picked from commit 1c26f43)
1 parent 1aa7a50 commit d87f8f9

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;
@@ -3377,6 +3376,7 @@ void jl_init_types(void) JL_GC_DISABLED
33773376
core = jl_core_module;
33783377
jl_method_table->module = core;
33793378
jl_atomic_store_relaxed(&jl_method_table->cache->leafcache, (jl_genericmemory_t*)jl_an_empty_memory_any);
3379+
jl_method_table->backedges = (jl_genericmemory_t*)jl_an_empty_memory_any;
33803380
jl_atomic_store_relaxed(&core->bindingkeyset, (jl_genericmemory_t*)jl_an_empty_memory_any);
33813381
// export own name, so "using Foo" makes "Foo" itself visible
33823382
jl_set_initial_const(core, core->name, (jl_value_t*)core, 1);
@@ -3841,13 +3841,13 @@ void jl_init_types(void) JL_GC_DISABLED
38413841
jl_svecset(jl_typename_type->types, 5, jl_voidpointer_type);
38423842
jl_svecset(jl_typename_type->types, 6, jl_type_type);
38433843
jl_svecset(jl_typename_type->types, 7, jl_type_type);
3844-
jl_svecset(jl_typename_type->types, 12, jl_long_type);
3844+
jl_svecset(jl_typename_type->types, 11, jl_long_type);
3845+
jl_svecset(jl_typename_type->types, 12, jl_int32_type);
38453846
jl_svecset(jl_typename_type->types, 13, jl_int32_type);
3846-
jl_svecset(jl_typename_type->types, 14, jl_int32_type);
3847+
jl_svecset(jl_typename_type->types, 14, jl_uint8_type);
38473848
jl_svecset(jl_typename_type->types, 15, jl_uint8_type);
38483849
jl_svecset(jl_typename_type->types, 16, jl_uint8_type);
38493850
jl_svecset(jl_typename_type->types, 17, jl_uint8_type);
3850-
jl_svecset(jl_typename_type->types, 18, jl_uint8_type);
38513851
jl_svecset(jl_methcache_type->types, 2, jl_long_type); // voidpointer
38523852
jl_svecset(jl_methcache_type->types, 3, jl_long_type); // uint32_t plus alignment
38533853
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
@@ -529,7 +529,6 @@ typedef struct {
529529
_Atomic(jl_value_t*) Typeofwrapper; // cache for Type{wrapper}
530530
_Atomic(jl_svec_t*) cache; // sorted array
531531
_Atomic(jl_svec_t*) linearcache; // unsorted array
532-
jl_array_t *backedges; // uncovered (sig => caller::CodeInstance) pairs with this type as the function
533532
jl_array_t *partial; // incomplete instantiations of this type
534533
intptr_t hash;
535534
_Atomic(int32_t) max_args; // max # of non-vararg arguments in a signature with this type as the function
@@ -891,6 +890,7 @@ typedef struct _jl_methtable_t {
891890
jl_methcache_t *cache;
892891
jl_sym_t *name; // sometimes used for debug printing
893892
jl_module_t *module; // sometimes used for debug printing
893+
jl_genericmemory_t *backedges; // IdDict{top typenames, Vector{uncovered (sig => caller::CodeInstance)}}
894894
} jl_methtable_t;
895895

896896
typedef struct {

src/julia_internal.h

Lines changed: 0 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -858,7 +858,6 @@ jl_expr_t *jl_exprn(jl_sym_t *head, size_t n);
858858
jl_function_t *jl_new_generic_function(jl_sym_t *name, jl_module_t *module, size_t new_world);
859859
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);
860860
int jl_foreach_reachable_mtable(int (*visit)(jl_methtable_t *mt, void *env), jl_array_t *mod_array, void *env);
861-
int foreach_mtable_in_module(jl_module_t *m, int (*visit)(jl_methtable_t *mt, void *env), void *env);
862861
void jl_init_main_module(void);
863862
JL_DLLEXPORT int jl_is_submodule(jl_module_t *child, jl_module_t *parent) JL_NOTSAFEPOINT;
864863
jl_array_t *jl_get_loaded_modules(void);
@@ -937,7 +936,6 @@ JL_DLLEXPORT jl_methtable_t *jl_method_get_table(
937936
jl_method_t *method JL_PROPAGATES_ROOT) JL_NOTSAFEPOINT;
938937
JL_DLLEXPORT jl_methcache_t *jl_method_get_cache(
939938
jl_method_t *method JL_PROPAGATES_ROOT) JL_NOTSAFEPOINT;
940-
void jl_foreach_top_typename_for(void (*f)(jl_typename_t*, void*), jl_value_t *argtypes JL_PROPAGATES_ROOT, void *env);
941939

942940
JL_DLLEXPORT int jl_pointer_egal(jl_value_t *t);
943941
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
}
@@ -2571,8 +2581,6 @@ static void jl_prune_mi_backedges(jl_array_t *backedges)
25712581

25722582
static void jl_prune_tn_backedges(jl_array_t *backedges)
25732583
{
2574-
if (backedges == NULL)
2575-
return;
25762584
size_t i = 0, ins = 0, n = jl_array_nrows(backedges);
25772585
for (i = 1; i < n; i += 2) {
25782586
jl_value_t *ci = jl_array_ptr_ref(backedges, i);
@@ -2584,6 +2592,15 @@ static void jl_prune_tn_backedges(jl_array_t *backedges)
25842592
jl_array_del_end(backedges, n - ins);
25852593
}
25862594

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

25882605
static void jl_prune_binding_backedges(jl_array_t *backedges)
25892606
{
@@ -3238,8 +3255,6 @@ static void jl_save_system_image_to_stream(ios_t *f, jl_array_t *mod_array,
32383255
jl_prune_type_cache_hash(jl_atomic_load_relaxed(&tn->cache)));
32393256
jl_gc_wb(tn, jl_atomic_load_relaxed(&tn->cache));
32403257
jl_prune_type_cache_linear(jl_atomic_load_relaxed(&tn->linearcache));
3241-
jl_value_t *backedges = get_replaceable_field((jl_value_t**)&tn->backedges, 1);
3242-
jl_prune_tn_backedges((jl_array_t*)backedges);
32433258
}
32443259
else if (jl_is_method_instance(v)) {
32453260
jl_method_instance_t *mi = (jl_method_instance_t*)v;
@@ -3251,6 +3266,11 @@ static void jl_save_system_image_to_stream(ios_t *f, jl_array_t *mod_array,
32513266
jl_value_t *backedges = get_replaceable_field((jl_value_t**)&b->backedges, 1);
32523267
jl_prune_binding_backedges((jl_array_t*)backedges);
32533268
}
3269+
else if (jl_is_mtable(v)) {
3270+
jl_methtable_t *mt = (jl_methtable_t*)v;
3271+
jl_value_t *backedges = get_replaceable_field((jl_value_t**)&mt->backedges, 1);
3272+
jl_prune_mt_backedges((jl_genericmemory_t*)backedges);
3273+
}
32543274
}
32553275
}
32563276

test/misc.jl

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1614,10 +1614,10 @@ end
16141614
let errs = IOBuffer()
16151615
run(`$(Base.julia_cmd()) -e '
16161616
using Test
1617-
@test isdefined(Type.body.name, :backedges)
1617+
@test !isempty(Core.GlobalMethods.backedges)
16181618
Base.Experimental.disable_new_worlds()
16191619
@test_throws "disable_new_worlds" @eval f() = 1
1620-
@test !isdefined(Type.body.name, :backedges)
1620+
@test isempty(Core.GlobalMethods.backedges)
16211621
@test_throws "disable_new_worlds" Base.delete_method(which(+, (Int, Int)))
16221622
@test 1+1 == 2
16231623
using Dates

0 commit comments

Comments
 (0)