Skip to content

Commit 9002fe5

Browse files
vtjnashKristofferC
authored andcommitted
staticdata: corrected implementation of jl_collect_new_roots (#57407)
This seems basically the same as #57212, but from computing and using `method_roots_list` wrong instead here (specifically the recursively part). Fix it by integrating `jl_collect_new_roots` with the places we actually need it. Fixes #56994 (cherry picked from commit f5f6d41)
1 parent 5918d42 commit 9002fe5

File tree

2 files changed

+69
-71
lines changed

2 files changed

+69
-71
lines changed

src/staticdata.c

Lines changed: 69 additions & 26 deletions
Original file line numberDiff line numberDiff line change
@@ -550,6 +550,9 @@ typedef struct {
550550
jl_array_t *link_ids_gctags;
551551
jl_array_t *link_ids_gvars;
552552
jl_array_t *link_ids_external_fnvars;
553+
jl_array_t *method_roots_list;
554+
htable_t method_roots_index;
555+
uint64_t worklist_key;
553556
jl_ptls_t ptls;
554557
jl_image_t *image;
555558
int8_t incremental;
@@ -931,22 +934,57 @@ static void jl_insert_into_serialization_queue(jl_serializer_state *s, jl_value_
931934
int is_relocatable = jl_is_code_info(inferred) ||
932935
(jl_is_string(inferred) && jl_string_len(inferred) > 0 && jl_string_data(inferred)[jl_string_len(inferred) - 1]);
933936
if (!is_relocatable) {
934-
record_field_change((jl_value_t**)&ci->inferred, jl_nothing);
937+
inferred = jl_nothing;
935938
}
936939
else if (def->source == NULL) {
937940
// don't delete code from optimized opaque closures that can't be reconstructed (and builtins)
938941
}
939942
else if (jl_atomic_load_relaxed(&ci->max_world) != ~(size_t)0 || // delete all code that cannot run
940943
jl_atomic_load_relaxed(&ci->invoke) == jl_fptr_const_return) { // delete all code that just returns a constant
941-
record_field_change((jl_value_t**)&ci->inferred, jl_nothing);
944+
inferred = jl_nothing;
942945
}
943946
else if (native_functions && // don't delete any code if making a ji file
944947
(ci->owner == jl_nothing) && // don't delete code for external interpreters
945948
!effects_foldable(jl_atomic_load_relaxed(&ci->ipo_purity_bits)) && // don't delete code we may want for irinterp
946949
jl_ir_inlining_cost(inferred) == UINT16_MAX) { // don't delete inlineable code
947950
// delete the code now: if we thought it was worth keeping, it would have been converted to object code
951+
inferred = jl_nothing;
952+
}
953+
if (inferred == jl_nothing) {
948954
record_field_change((jl_value_t**)&ci->inferred, jl_nothing);
949955
}
956+
else if (jl_is_string(inferred)) {
957+
// New roots for external methods
958+
if (jl_object_in_image((jl_value_t*)def)) {
959+
void **pfound = ptrhash_bp(&s->method_roots_index, def);
960+
if (*pfound == HT_NOTFOUND) {
961+
*pfound = def;
962+
size_t nwithkey = nroots_with_key(def, s->worklist_key);
963+
if (nwithkey) {
964+
jl_array_ptr_1d_push(s->method_roots_list, (jl_value_t*)def);
965+
jl_array_t *newroots = jl_alloc_vec_any(nwithkey);
966+
jl_array_ptr_1d_push(s->method_roots_list, (jl_value_t*)newroots);
967+
rle_iter_state rootiter = rle_iter_init(0);
968+
uint64_t *rletable = NULL;
969+
size_t nblocks2 = 0;
970+
size_t nroots = jl_array_nrows(def->roots);
971+
size_t k = 0;
972+
if (def->root_blocks) {
973+
rletable = jl_array_data(def->root_blocks, uint64_t);
974+
nblocks2 = jl_array_nrows(def->root_blocks);
975+
}
976+
while (rle_iter_increment(&rootiter, nroots, rletable, nblocks2)) {
977+
if (rootiter.key == s->worklist_key) {
978+
jl_value_t *newroot = jl_array_ptr_ref(def->roots, rootiter.i);
979+
jl_queue_for_serialization(s, newroot);
980+
jl_array_ptr_set(newroots, k++, newroot);
981+
}
982+
}
983+
assert(k == nwithkey);
984+
}
985+
}
986+
}
987+
}
950988
}
951989
}
952990
}
@@ -2861,10 +2899,9 @@ JL_DLLEXPORT jl_value_t *jl_as_global_root(jl_value_t *val, int insert)
28612899
return val;
28622900
}
28632901

2864-
static void jl_prepare_serialization_data(jl_array_t *mod_array, jl_array_t *newly_inferred, uint64_t worklist_key,
2902+
static void jl_prepare_serialization_data(jl_array_t *mod_array, jl_array_t *newly_inferred,
28652903
/* outputs */ jl_array_t **extext_methods JL_REQUIRE_ROOTED_SLOT,
28662904
jl_array_t **new_ext_cis JL_REQUIRE_ROOTED_SLOT,
2867-
jl_array_t **method_roots_list JL_REQUIRE_ROOTED_SLOT,
28682905
jl_array_t **edges JL_REQUIRE_ROOTED_SLOT)
28692906
{
28702907
// extext_methods: [method1, ...], worklist-owned "extending external" methods added to functions owned by modules outside the worklist
@@ -2888,24 +2925,20 @@ static void jl_prepare_serialization_data(jl_array_t *mod_array, jl_array_t *new
28882925
}
28892926

28902927
if (edges) {
2928+
// Extract `edges` now (from info prepared by jl_collect_methcache_from_mod)
28912929
size_t world = jl_atomic_load_acquire(&jl_world_counter);
2892-
// Extract `new_ext_cis` and `edges` now (from info prepared by jl_collect_methcache_from_mod)
2893-
*method_roots_list = jl_alloc_vec_any(0);
2894-
// Collect the new method roots for external specializations
2895-
jl_collect_new_roots(*method_roots_list, *new_ext_cis, worklist_key);
28962930
*edges = jl_alloc_vec_any(0);
28972931
jl_collect_internal_cis(*edges, world);
28982932
}
2899-
internal_methods = NULL;
2933+
internal_methods = NULL; // global
29002934

29012935
JL_GC_POP();
29022936
}
29032937

29042938
// In addition to the system image (where `worklist = NULL`), this can also save incremental images with external linkage
29052939
static void jl_save_system_image_to_stream(ios_t *f, jl_array_t *mod_array,
29062940
jl_array_t *worklist, jl_array_t *extext_methods,
2907-
jl_array_t *new_ext_cis, jl_array_t *method_roots_list,
2908-
jl_array_t *edges) JL_GC_DISABLED
2941+
jl_array_t *new_ext_cis, jl_array_t *edges)
29092942
{
29102943
htable_new(&field_replace, 0);
29112944
htable_new(&bits_replace, 0);
@@ -3035,9 +3068,14 @@ static void jl_save_system_image_to_stream(ios_t *f, jl_array_t *mod_array,
30353068
s.link_ids_gctags = jl_alloc_array_1d(jl_array_int32_type, 0);
30363069
s.link_ids_gvars = jl_alloc_array_1d(jl_array_int32_type, 0);
30373070
s.link_ids_external_fnvars = jl_alloc_array_1d(jl_array_int32_type, 0);
3071+
s.method_roots_list = NULL;
3072+
htable_new(&s.method_roots_index, 0);
3073+
if (worklist) {
3074+
s.method_roots_list = jl_alloc_vec_any(0);
3075+
s.worklist_key = jl_worklist_key(worklist);
3076+
}
30383077
jl_value_t **const*const tags = get_tags(); // worklist == NULL ? get_tags() : NULL;
30393078

3040-
30413079
if (worklist == NULL) {
30423080
// empty!(Core.ARGS)
30433081
if (jl_core_module != NULL) {
@@ -3082,8 +3120,6 @@ static void jl_save_system_image_to_stream(ios_t *f, jl_array_t *mod_array,
30823120
jl_queue_for_serialization(&s, extext_methods);
30833121
// Queue the new specializations
30843122
jl_queue_for_serialization(&s, new_ext_cis);
3085-
// Queue the new roots
3086-
jl_queue_for_serialization(&s, method_roots_list);
30873123
// Queue the edges
30883124
jl_queue_for_serialization(&s, edges);
30893125
}
@@ -3094,7 +3130,15 @@ static void jl_save_system_image_to_stream(ios_t *f, jl_array_t *mod_array,
30943130
if (jl_options.trim)
30953131
record_gvars(&s, &MIs);
30963132
jl_serialize_reachable(&s);
3097-
// step 1.3: prune (garbage collect) special weak references from the jl_global_roots_list
3133+
// Beyond this point, all content should already have been visited, so now we can prune
3134+
// the rest and add some internal root arrays.
3135+
// step 1.3: include some other special roots
3136+
if (s.incremental) {
3137+
// Queue the new roots array
3138+
jl_queue_for_serialization(&s, s.method_roots_list);
3139+
jl_serialize_reachable(&s);
3140+
}
3141+
// step 1.4: prune (garbage collect) special weak references from the jl_global_roots_list
30983142
if (worklist == NULL) {
30993143
global_roots_list = jl_alloc_memory_any(0);
31003144
global_roots_keyset = jl_alloc_memory_any(0);
@@ -3110,7 +3154,7 @@ static void jl_save_system_image_to_stream(ios_t *f, jl_array_t *mod_array,
31103154
jl_queue_for_serialization(&s, global_roots_keyset);
31113155
jl_serialize_reachable(&s);
31123156
}
3113-
// step 1.4: prune (garbage collect) some special weak references from
3157+
// step 1.5: prune (garbage collect) some special weak references from
31143158
// built-in type caches too
31153159
for (i = 0; i < serialization_queue.len; i++) {
31163160
jl_value_t *v = (jl_value_t*)serialization_queue.items[i];
@@ -3130,7 +3174,8 @@ static void jl_save_system_image_to_stream(ios_t *f, jl_array_t *mod_array,
31303174
if (ptrhash_get(&serialization_order, mi) == HT_NOTFOUND)
31313175
jl_svecset(specializations, i, jl_nothing);
31323176
}
3133-
} else if (jl_is_module(v)) {
3177+
}
3178+
else if (jl_is_module(v)) {
31343179
jl_prune_module_bindings((jl_module_t*)v);
31353180
}
31363181
}
@@ -3262,7 +3307,7 @@ static void jl_save_system_image_to_stream(ios_t *f, jl_array_t *mod_array,
32623307
jl_write_value(&s, jl_module_init_order);
32633308
jl_write_value(&s, extext_methods);
32643309
jl_write_value(&s, new_ext_cis);
3265-
jl_write_value(&s, method_roots_list);
3310+
jl_write_value(&s, s.method_roots_list);
32663311
jl_write_value(&s, edges);
32673312
}
32683313
write_uint32(f, jl_array_len(s.link_ids_gctags));
@@ -3293,6 +3338,7 @@ static void jl_save_system_image_to_stream(ios_t *f, jl_array_t *mod_array,
32933338
arraylist_free(&s.gctags_list);
32943339
arraylist_free(&gvars);
32953340
arraylist_free(&external_fns);
3341+
htable_free(&s.method_roots_index);
32963342
htable_free(&field_replace);
32973343
htable_free(&bits_replace);
32983344
htable_free(&serialization_order);
@@ -3353,18 +3399,17 @@ JL_DLLEXPORT void jl_create_system_image(void **_native_data, jl_array_t *workli
33533399
}
33543400

33553401
jl_array_t *mod_array = NULL, *extext_methods = NULL, *new_ext_cis = NULL;
3356-
jl_array_t *method_roots_list = NULL, *edges = NULL;
3402+
jl_array_t *edges = NULL;
33573403
int64_t checksumpos = 0;
33583404
int64_t checksumpos_ff = 0;
33593405
int64_t datastartpos = 0;
3360-
JL_GC_PUSH5(&mod_array, &extext_methods, &new_ext_cis, &method_roots_list, &edges);
3406+
JL_GC_PUSH4(&mod_array, &extext_methods, &new_ext_cis, &edges);
33613407

33623408
if (worklist) {
33633409
mod_array = jl_get_loaded_modules(); // __toplevel__ modules loaded in this session (from Base.loaded_modules_array)
33643410
// Generate _native_data`
33653411
if (_native_data != NULL) {
3366-
jl_prepare_serialization_data(mod_array, newly_inferred, jl_worklist_key(worklist),
3367-
&extext_methods, &new_ext_cis, NULL, NULL);
3412+
jl_prepare_serialization_data(mod_array, newly_inferred, &extext_methods, &new_ext_cis, NULL);
33683413
jl_precompile_toplevel_module = (jl_module_t*)jl_array_ptr_ref(worklist, jl_array_len(worklist)-1);
33693414
*_native_data = jl_precompile_worklist(worklist, extext_methods, new_ext_cis);
33703415
jl_precompile_toplevel_module = NULL;
@@ -3395,8 +3440,7 @@ JL_DLLEXPORT void jl_create_system_image(void **_native_data, jl_array_t *workli
33953440
assert((ct->reentrant_timing & 0b1110) == 0);
33963441
ct->reentrant_timing |= 0b1000;
33973442
if (worklist) {
3398-
jl_prepare_serialization_data(mod_array, newly_inferred, jl_worklist_key(worklist),
3399-
&extext_methods, &new_ext_cis, &method_roots_list, &edges);
3443+
jl_prepare_serialization_data(mod_array, newly_inferred, &extext_methods, &new_ext_cis, &edges);
34003444
if (!emit_split) {
34013445
write_int32(f, 0); // No clone_targets
34023446
write_padding(f, LLT_ALIGN(ios_pos(f), JL_CACHE_BYTE_ALIGNMENT) - ios_pos(f));
@@ -3408,7 +3452,7 @@ JL_DLLEXPORT void jl_create_system_image(void **_native_data, jl_array_t *workli
34083452
}
34093453
if (_native_data != NULL)
34103454
native_functions = *_native_data;
3411-
jl_save_system_image_to_stream(ff, mod_array, worklist, extext_methods, new_ext_cis, method_roots_list, edges);
3455+
jl_save_system_image_to_stream(ff, mod_array, worklist, extext_methods, new_ext_cis, edges);
34123456
if (_native_data != NULL)
34133457
native_functions = NULL;
34143458
// make sure we don't run any Julia code concurrently before this point
@@ -4185,7 +4229,6 @@ static jl_value_t *jl_restore_package_image_from_stream(void* pkgimage_handle, i
41854229
&edges, &base, &ccallable_list, &cachesizes);
41864230
JL_SIGATOMIC_END();
41874231

4188-
// No special processing of `new_ext_cis` is required because recaching handled it
41894232
// Add roots to methods
41904233
jl_copy_roots(method_roots_list, jl_worklist_key((jl_array_t*)restored));
41914234
// Insert method extensions and handle edges

src/staticdata_utils.c

Lines changed: 0 additions & 45 deletions
Original file line numberDiff line numberDiff line change
@@ -261,51 +261,6 @@ static jl_array_t *queue_external_cis(jl_array_t *list)
261261
return new_ext_cis;
262262
}
263263

264-
// New roots for external methods
265-
static void jl_collect_new_roots(jl_array_t *roots, jl_array_t *new_ext_cis, uint64_t key)
266-
{
267-
htable_t mset;
268-
htable_new(&mset, 0);
269-
size_t l = new_ext_cis ? jl_array_nrows(new_ext_cis) : 0;
270-
for (size_t i = 0; i < l; i++) {
271-
jl_code_instance_t *ci = (jl_code_instance_t*)jl_array_ptr_ref(new_ext_cis, i);
272-
assert(jl_is_code_instance(ci));
273-
jl_method_t *m = jl_get_ci_mi(ci)->def.method;
274-
assert(jl_is_method(m));
275-
ptrhash_put(&mset, (void*)m, (void*)m);
276-
}
277-
int nwithkey;
278-
void *const *table = mset.table;
279-
jl_array_t *newroots = NULL;
280-
JL_GC_PUSH1(&newroots);
281-
for (size_t i = 0; i < mset.size; i += 2) {
282-
if (table[i+1] != HT_NOTFOUND) {
283-
jl_method_t *m = (jl_method_t*)table[i];
284-
assert(jl_is_method(m));
285-
nwithkey = nroots_with_key(m, key);
286-
if (nwithkey) {
287-
jl_array_ptr_1d_push(roots, (jl_value_t*)m);
288-
newroots = jl_alloc_vec_any(nwithkey);
289-
jl_array_ptr_1d_push(roots, (jl_value_t*)newroots);
290-
rle_iter_state rootiter = rle_iter_init(0);
291-
uint64_t *rletable = NULL;
292-
size_t nblocks2 = 0, nroots = jl_array_nrows(m->roots), k = 0;
293-
if (m->root_blocks) {
294-
rletable = jl_array_data(m->root_blocks, uint64_t);
295-
nblocks2 = jl_array_nrows(m->root_blocks);
296-
}
297-
while (rle_iter_increment(&rootiter, nroots, rletable, nblocks2))
298-
if (rootiter.key == key)
299-
jl_array_ptr_set(newroots, k++, jl_array_ptr_ref(m->roots, rootiter.i));
300-
assert(k == nwithkey);
301-
}
302-
}
303-
}
304-
JL_GC_POP();
305-
htable_free(&mset);
306-
}
307-
308-
309264
// For every method:
310265
// - if the method is owned by a worklist module, add it to the list of things to be
311266
// verified on reloading

0 commit comments

Comments
 (0)