@@ -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
29052939static 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
0 commit comments