@@ -90,6 +90,22 @@ static const size_t WORLD_AGE_REVALIDATION_SENTINEL = 0x1;
9090JL_DLLEXPORT size_t jl_require_world = ~(size_t )0 ;
9191JL_DLLEXPORT _Atomic(size_t ) jl_first_image_replacement_world = ~(size_t )0 ;
9292
93+ // This structure is used to store hash tables for the memoization
94+ // of queries in staticdata.c (currently only `type_in_worklist`).
95+ typedef struct {
96+ htable_t type_in_worklist ;
97+ } jl_query_cache ;
98+
99+ static void init_query_cache (jl_query_cache * cache )
100+ {
101+ htable_new (& cache -> type_in_worklist , 0 );
102+ }
103+
104+ static void destroy_query_cache (jl_query_cache * cache )
105+ {
106+ htable_free (& cache -> type_in_worklist );
107+ }
108+
93109#include "staticdata_utils.c"
94110#include "precompile_utils.c"
95111
@@ -552,6 +568,7 @@ typedef struct {
552568 jl_array_t * method_roots_list ;
553569 htable_t method_roots_index ;
554570 uint64_t worklist_key ;
571+ jl_query_cache * query_cache ;
555572 jl_ptls_t ptls ;
556573 jl_image_t * image ;
557574 int8_t incremental ;
@@ -675,14 +692,13 @@ static int jl_needs_serialization(jl_serializer_state *s, jl_value_t *v) JL_NOTS
675692 return 1 ;
676693}
677694
678-
679- static int caching_tag (jl_value_t * v ) JL_NOTSAFEPOINT
695+ static int caching_tag (jl_value_t * v , jl_query_cache * query_cache ) JL_NOTSAFEPOINT
680696{
681697 if (jl_is_method_instance (v )) {
682698 jl_method_instance_t * mi = (jl_method_instance_t * )v ;
683699 jl_value_t * m = mi -> def .value ;
684700 if (jl_is_method (m ) && jl_object_in_image (m ))
685- return 1 + type_in_worklist (mi -> specTypes );
701+ return 1 + type_in_worklist (mi -> specTypes , query_cache );
686702 }
687703 if (jl_is_binding (v )) {
688704 jl_globalref_t * gr = ((jl_binding_t * )v )-> globalref ;
@@ -697,24 +713,24 @@ static int caching_tag(jl_value_t *v) JL_NOTSAFEPOINT
697713 if (jl_is_tuple_type (dt ) ? !dt -> isconcretetype : dt -> hasfreetypevars )
698714 return 0 ; // aka !is_cacheable from jltypes.c
699715 if (jl_object_in_image ((jl_value_t * )dt -> name ))
700- return 1 + type_in_worklist (v );
716+ return 1 + type_in_worklist (v , query_cache );
701717 }
702718 jl_value_t * dtv = jl_typeof (v );
703719 if (jl_is_datatype_singleton ((jl_datatype_t * )dtv )) {
704- return 1 - type_in_worklist (dtv ); // these are already recached in the datatype in the image
720+ return 1 - type_in_worklist (dtv , query_cache ); // these are already recached in the datatype in the image
705721 }
706722 return 0 ;
707723}
708724
709- static int needs_recaching (jl_value_t * v ) JL_NOTSAFEPOINT
725+ static int needs_recaching (jl_value_t * v , jl_query_cache * query_cache ) JL_NOTSAFEPOINT
710726{
711- return caching_tag (v ) == 2 ;
727+ return caching_tag (v , query_cache ) == 2 ;
712728}
713729
714- static int needs_uniquing (jl_value_t * v ) JL_NOTSAFEPOINT
730+ static int needs_uniquing (jl_value_t * v , jl_query_cache * query_cache ) JL_NOTSAFEPOINT
715731{
716732 assert (!jl_object_in_image (v ));
717- return caching_tag (v ) == 1 ;
733+ return caching_tag (v , query_cache ) == 1 ;
718734}
719735
720736static void record_field_change (jl_value_t * * addr , jl_value_t * newval ) JL_NOTSAFEPOINT
@@ -798,7 +814,6 @@ static void jl_queue_module_for_serialization(jl_serializer_state *s, jl_module_
798814 // ... or point to Base functions accessed by the runtime
799815 (m == jl_base_module && (!strcmp (jl_symbol_name (b -> globalref -> name ), "wait" ) ||
800816 !strcmp (jl_symbol_name (b -> globalref -> name ), "task_done_hook" ))))) {
801- record_field_change ((jl_value_t * * )& b -> backedges , NULL );
802817 jl_queue_for_serialization (s , b );
803818 }
804819 }
@@ -840,7 +855,7 @@ static void jl_insert_into_serialization_queue(jl_serializer_state *s, jl_value_
840855 jl_datatype_t * dt = (jl_datatype_t * )v ;
841856 // ensure all type parameters are recached
842857 jl_queue_for_serialization_ (s , (jl_value_t * )dt -> parameters , 1 , 1 );
843- if (jl_is_datatype_singleton (dt ) && needs_uniquing (dt -> instance )) {
858+ if (jl_is_datatype_singleton (dt ) && needs_uniquing (dt -> instance , s -> query_cache )) {
844859 assert (jl_needs_serialization (s , dt -> instance )); // should be true, since we visited dt
845860 // do not visit dt->instance for our template object as it leads to unwanted cycles here
846861 // (it may get serialized from elsewhere though)
@@ -851,7 +866,7 @@ static void jl_insert_into_serialization_queue(jl_serializer_state *s, jl_value_
851866 if (s -> incremental && jl_is_method_instance (v )) {
852867 jl_method_instance_t * mi = (jl_method_instance_t * )v ;
853868 jl_value_t * def = mi -> def .value ;
854- if (needs_uniquing (v )) {
869+ if (needs_uniquing (v , s -> query_cache )) {
855870 // we only need 3 specific fields of this (the rest are not used)
856871 jl_queue_for_serialization (s , mi -> def .value );
857872 jl_queue_for_serialization (s , mi -> specTypes );
@@ -866,7 +881,7 @@ static void jl_insert_into_serialization_queue(jl_serializer_state *s, jl_value_
866881 record_field_change ((jl_value_t * * )& mi -> cache , NULL );
867882 }
868883 else {
869- assert (!needs_recaching (v ));
884+ assert (!needs_recaching (v , s -> query_cache ));
870885 }
871886 // n.b. opaque closures cannot be inspected and relied upon like a
872887 // normal method since they can get improperly introduced by generated
@@ -876,7 +891,7 @@ static void jl_insert_into_serialization_queue(jl_serializer_state *s, jl_value_
876891 // error now.
877892 }
878893 if (s -> incremental && jl_is_binding (v )) {
879- if (needs_uniquing (v )) {
894+ if (needs_uniquing (v , s -> query_cache )) {
880895 jl_binding_t * b = (jl_binding_t * )v ;
881896 jl_queue_for_serialization (s , b -> globalref -> mod );
882897 jl_queue_for_serialization (s , b -> globalref -> name );
@@ -1044,6 +1059,9 @@ static void jl_insert_into_serialization_queue(jl_serializer_state *s, jl_value_
10441059 record_field_change ((jl_value_t * * )& tn -> mt , NULL );
10451060 }
10461061 }
1062+ else if (jl_is_binding (v )) {
1063+ record_field_change ((jl_value_t * * )& ((jl_binding_t * )v )-> backedges , NULL );
1064+ }
10471065 }
10481066 char * data = (char * )jl_data_ptr (v );
10491067 size_t i , np = layout -> npointers ;
@@ -1100,9 +1118,9 @@ static void jl_queue_for_serialization_(jl_serializer_state *s, jl_value_t *v, i
11001118 // Items that require postorder traversal must visit their children prior to insertion into
11011119 // the worklist/serialization_order (and also before their first use)
11021120 if (s -> incremental && !immediate ) {
1103- if (jl_is_datatype (t ) && needs_uniquing (v ))
1121+ if (jl_is_datatype (t ) && needs_uniquing (v , s -> query_cache ))
11041122 immediate = 1 ;
1105- if (jl_is_datatype_singleton ((jl_datatype_t * )t ) && needs_uniquing (v ))
1123+ if (jl_is_datatype_singleton ((jl_datatype_t * )t ) && needs_uniquing (v , s -> query_cache ))
11061124 immediate = 1 ;
11071125 }
11081126
@@ -1265,7 +1283,7 @@ static uintptr_t _backref_id(jl_serializer_state *s, jl_value_t *v, jl_array_t *
12651283
12661284static void record_uniquing (jl_serializer_state * s , jl_value_t * fld , uintptr_t offset ) JL_NOTSAFEPOINT
12671285{
1268- if (s -> incremental && jl_needs_serialization (s , fld ) && needs_uniquing (fld )) {
1286+ if (s -> incremental && jl_needs_serialization (s , fld ) && needs_uniquing (fld , s -> query_cache )) {
12691287 if (jl_is_datatype (fld ) || jl_is_datatype_singleton ((jl_datatype_t * )jl_typeof (fld )))
12701288 arraylist_push (& s -> uniquing_types , (void * )(uintptr_t )offset );
12711289 else if (jl_is_method_instance (fld ) || jl_is_binding (fld ))
@@ -1489,7 +1507,7 @@ static void jl_write_values(jl_serializer_state *s) JL_GC_DISABLED
14891507 // write header
14901508 if (object_id_expected )
14911509 write_uint (f , jl_object_id (v ));
1492- if (s -> incremental && jl_needs_serialization (s , (jl_value_t * )t ) && needs_uniquing ((jl_value_t * )t ))
1510+ if (s -> incremental && jl_needs_serialization (s , (jl_value_t * )t ) && needs_uniquing ((jl_value_t * )t , s -> query_cache ))
14931511 arraylist_push (& s -> uniquing_types , (void * )(uintptr_t )(ios_pos (f )|1 ));
14941512 if (f == s -> const_data )
14951513 write_uint (s -> const_data , ((uintptr_t )t -> smalltag << 4 ) | GC_OLD_MARKED | GC_IN_IMAGE );
@@ -1500,7 +1518,7 @@ static void jl_write_values(jl_serializer_state *s) JL_GC_DISABLED
15001518 layout_table .items [item ] = (void * )(reloc_offset | (f == s -> const_data )); // store the inverse mapping of `serialization_order` (`id` => object-as-streampos)
15011519
15021520 if (s -> incremental ) {
1503- if (needs_uniquing (v )) {
1521+ if (needs_uniquing (v , s -> query_cache )) {
15041522 if (jl_typetagis (v , jl_binding_type )) {
15051523 jl_binding_t * b = (jl_binding_t * )v ;
15061524 if (b -> globalref == NULL )
@@ -1529,7 +1547,7 @@ static void jl_write_values(jl_serializer_state *s) JL_GC_DISABLED
15291547 assert (jl_is_datatype_singleton (t ) && "unreachable" );
15301548 }
15311549 }
1532- else if (needs_recaching (v )) {
1550+ else if (needs_recaching (v , s -> query_cache )) {
15331551 arraylist_push (jl_is_datatype (v ) ? & s -> fixup_types : & s -> fixup_objs , (void * )reloc_offset );
15341552 }
15351553 }
@@ -1962,7 +1980,7 @@ static void jl_write_values(jl_serializer_state *s) JL_GC_DISABLED
19621980 }
19631981 }
19641982 void * superidx = ptrhash_get (& serialization_order , dt -> super );
1965- if (s -> incremental && superidx != HT_NOTFOUND && from_seroder_entry (superidx ) > item && needs_uniquing ((jl_value_t * )dt -> super ))
1983+ if (s -> incremental && superidx != HT_NOTFOUND && from_seroder_entry (superidx ) > item && needs_uniquing ((jl_value_t * )dt -> super , s -> query_cache ))
19661984 arraylist_push (& s -> uniquing_super , dt -> super );
19671985 }
19681986 else if (jl_is_typename (v )) {
@@ -2873,13 +2891,14 @@ JL_DLLEXPORT jl_value_t *jl_as_global_root(jl_value_t *val, int insert)
28732891static void jl_prepare_serialization_data (jl_array_t * mod_array , jl_array_t * newly_inferred ,
28742892 /* outputs */ jl_array_t * * extext_methods JL_REQUIRE_ROOTED_SLOT ,
28752893 jl_array_t * * new_ext_cis JL_REQUIRE_ROOTED_SLOT ,
2876- jl_array_t * * edges JL_REQUIRE_ROOTED_SLOT )
2894+ jl_array_t * * edges JL_REQUIRE_ROOTED_SLOT ,
2895+ jl_query_cache * query_cache )
28772896{
28782897 // extext_methods: [method1, ...], worklist-owned "extending external" methods added to functions owned by modules outside the worklist
28792898 // edges: [caller1, ext_targets, ...] for worklist-owned methods calling external methods
28802899
28812900 // Save the inferred code from newly inferred, external methods
2882- * new_ext_cis = queue_external_cis (newly_inferred );
2901+ * new_ext_cis = queue_external_cis (newly_inferred , query_cache );
28832902
28842903 // Collect method extensions and edges data
28852904 * extext_methods = jl_alloc_vec_any (0 );
@@ -2909,7 +2928,8 @@ static void jl_prepare_serialization_data(jl_array_t *mod_array, jl_array_t *new
29092928// In addition to the system image (where `worklist = NULL`), this can also save incremental images with external linkage
29102929static void jl_save_system_image_to_stream (ios_t * f , jl_array_t * mod_array ,
29112930 jl_array_t * worklist , jl_array_t * extext_methods ,
2912- jl_array_t * new_ext_cis , jl_array_t * edges )
2931+ jl_array_t * new_ext_cis , jl_array_t * edges ,
2932+ jl_query_cache * query_cache )
29132933{
29142934 htable_new (& field_replace , 0 );
29152935 htable_new (& bits_replace , 0 );
@@ -3016,6 +3036,7 @@ static void jl_save_system_image_to_stream(ios_t *f, jl_array_t *mod_array,
30163036 ios_mem (& gvar_record , 0 );
30173037 ios_mem (& fptr_record , 0 );
30183038 jl_serializer_state s = {0 };
3039+ s .query_cache = query_cache ;
30193040 s .incremental = !(worklist == NULL );
30203041 s .s = & sysimg ;
30213042 s .const_data = & const_data ;
@@ -3373,11 +3394,14 @@ JL_DLLEXPORT void jl_create_system_image(void **_native_data, jl_array_t *workli
33733394 int64_t datastartpos = 0 ;
33743395 JL_GC_PUSH4 (& mod_array , & extext_methods , & new_ext_cis , & edges );
33753396
3397+ jl_query_cache query_cache ;
3398+ init_query_cache (& query_cache );
3399+
33763400 if (worklist ) {
33773401 mod_array = jl_get_loaded_modules (); // __toplevel__ modules loaded in this session (from Base.loaded_modules_array)
33783402 // Generate _native_data`
33793403 if (_native_data != NULL ) {
3380- jl_prepare_serialization_data (mod_array , newly_inferred , & extext_methods , & new_ext_cis , NULL );
3404+ jl_prepare_serialization_data (mod_array , newly_inferred , & extext_methods , & new_ext_cis , NULL , & query_cache );
33813405 jl_precompile_toplevel_module = (jl_module_t * )jl_array_ptr_ref (worklist , jl_array_len (worklist )- 1 );
33823406 * _native_data = jl_precompile_worklist (worklist , extext_methods , new_ext_cis );
33833407 jl_precompile_toplevel_module = NULL ;
@@ -3408,7 +3432,7 @@ JL_DLLEXPORT void jl_create_system_image(void **_native_data, jl_array_t *workli
34083432 assert ((ct -> reentrant_timing & 0b1110 ) == 0 );
34093433 ct -> reentrant_timing |= 0b1000 ;
34103434 if (worklist ) {
3411- jl_prepare_serialization_data (mod_array , newly_inferred , & extext_methods , & new_ext_cis , & edges );
3435+ jl_prepare_serialization_data (mod_array , newly_inferred , & extext_methods , & new_ext_cis , & edges , & query_cache );
34123436 if (!emit_split ) {
34133437 write_int32 (f , 0 ); // No clone_targets
34143438 write_padding (f , LLT_ALIGN (ios_pos (f ), JL_CACHE_BYTE_ALIGNMENT ) - ios_pos (f ));
@@ -3420,7 +3444,7 @@ JL_DLLEXPORT void jl_create_system_image(void **_native_data, jl_array_t *workli
34203444 }
34213445 if (_native_data != NULL )
34223446 native_functions = * _native_data ;
3423- jl_save_system_image_to_stream (ff , mod_array , worklist , extext_methods , new_ext_cis , edges );
3447+ jl_save_system_image_to_stream (ff , mod_array , worklist , extext_methods , new_ext_cis , edges , & query_cache );
34243448 if (_native_data != NULL )
34253449 native_functions = NULL ;
34263450 // make sure we don't run any Julia code concurrently before this point
@@ -3449,6 +3473,8 @@ JL_DLLEXPORT void jl_create_system_image(void **_native_data, jl_array_t *workli
34493473 }
34503474 }
34513475
3476+ destroy_query_cache (& query_cache );
3477+
34523478 JL_GC_POP ();
34533479 * s = f ;
34543480 if (emit_split )
0 commit comments