@@ -90,6 +90,22 @@ External links:
9090
9191static const size_t WORLD_AGE_REVALIDATION_SENTINEL = 0x1 ;
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
@@ -512,6 +528,7 @@ typedef struct {
512528 jl_array_t * link_ids_gctags ;
513529 jl_array_t * link_ids_gvars ;
514530 jl_array_t * link_ids_external_fnvars ;
531+ jl_query_cache * query_cache ;
515532 jl_ptls_t ptls ;
516533 // Set (implemented has a hasmap of MethodInstances to themselves) of which MethodInstances have (forward) edges
517534 // to other MethodInstances.
@@ -658,38 +675,37 @@ static int jl_needs_serialization(jl_serializer_state *s, jl_value_t *v) JL_NOTS
658675 return 1 ;
659676}
660677
661-
662- static int caching_tag (jl_value_t * v ) JL_NOTSAFEPOINT
678+ static int caching_tag (jl_value_t * v , jl_query_cache * query_cache ) JL_NOTSAFEPOINT
663679{
664680 if (jl_is_method_instance (v )) {
665681 jl_method_instance_t * mi = (jl_method_instance_t * )v ;
666682 jl_value_t * m = mi -> def .value ;
667683 if (jl_is_method (m ) && jl_object_in_image (m ))
668- return 1 + type_in_worklist (mi -> specTypes );
684+ return 1 + type_in_worklist (mi -> specTypes , query_cache );
669685 }
670686 if (jl_is_datatype (v )) {
671687 jl_datatype_t * dt = (jl_datatype_t * )v ;
672688 if (jl_is_tuple_type (dt ) ? !dt -> isconcretetype : dt -> hasfreetypevars )
673689 return 0 ; // aka !is_cacheable from jltypes.c
674690 if (jl_object_in_image ((jl_value_t * )dt -> name ))
675- return 1 + type_in_worklist (v );
691+ return 1 + type_in_worklist (v , query_cache );
676692 }
677693 jl_value_t * dtv = jl_typeof (v );
678694 if (jl_is_datatype_singleton ((jl_datatype_t * )dtv )) {
679- return 1 - type_in_worklist (dtv ); // these are already recached in the datatype in the image
695+ return 1 - type_in_worklist (dtv , query_cache ); // these are already recached in the datatype in the image
680696 }
681697 return 0 ;
682698}
683699
684- static int needs_recaching (jl_value_t * v ) JL_NOTSAFEPOINT
700+ static int needs_recaching (jl_value_t * v , jl_query_cache * query_cache ) JL_NOTSAFEPOINT
685701{
686- return caching_tag (v ) == 2 ;
702+ return caching_tag (v , query_cache ) == 2 ;
687703}
688704
689- static int needs_uniquing (jl_value_t * v ) JL_NOTSAFEPOINT
705+ static int needs_uniquing (jl_value_t * v , jl_query_cache * query_cache ) JL_NOTSAFEPOINT
690706{
691707 assert (!jl_object_in_image (v ));
692- return caching_tag (v ) == 1 ;
708+ return caching_tag (v , query_cache ) == 1 ;
693709}
694710
695711static void record_field_change (jl_value_t * * addr , jl_value_t * newval ) JL_NOTSAFEPOINT
@@ -774,7 +790,7 @@ static void jl_insert_into_serialization_queue(jl_serializer_state *s, jl_value_
774790 jl_datatype_t * dt = (jl_datatype_t * )v ;
775791 // ensure all type parameters are recached
776792 jl_queue_for_serialization_ (s , (jl_value_t * )dt -> parameters , 1 , 1 );
777- if (jl_is_datatype_singleton (dt ) && needs_uniquing (dt -> instance )) {
793+ if (jl_is_datatype_singleton (dt ) && needs_uniquing (dt -> instance , s -> query_cache )) {
778794 assert (jl_needs_serialization (s , dt -> instance )); // should be true, since we visited dt
779795 // do not visit dt->instance for our template object as it leads to unwanted cycles here
780796 // (it may get serialized from elsewhere though)
@@ -785,7 +801,7 @@ static void jl_insert_into_serialization_queue(jl_serializer_state *s, jl_value_
785801 if (s -> incremental && jl_is_method_instance (v )) {
786802 jl_method_instance_t * mi = (jl_method_instance_t * )v ;
787803 jl_value_t * def = mi -> def .value ;
788- if (needs_uniquing (v )) {
804+ if (needs_uniquing (v , s -> query_cache )) {
789805 // we only need 3 specific fields of this (the rest are not used)
790806 jl_queue_for_serialization (s , mi -> def .value );
791807 jl_queue_for_serialization (s , mi -> specTypes );
@@ -801,7 +817,7 @@ static void jl_insert_into_serialization_queue(jl_serializer_state *s, jl_value_
801817 record_field_change ((jl_value_t * * )& mi -> cache , NULL );
802818 }
803819 else {
804- assert (!needs_recaching (v ));
820+ assert (!needs_recaching (v , s -> query_cache ));
805821 }
806822 // n.b. opaque closures cannot be inspected and relied upon like a
807823 // normal method since they can get improperly introduced by generated
@@ -947,9 +963,9 @@ static void jl_queue_for_serialization_(jl_serializer_state *s, jl_value_t *v, i
947963 // Items that require postorder traversal must visit their children prior to insertion into
948964 // the worklist/serialization_order (and also before their first use)
949965 if (s -> incremental && !immediate ) {
950- if (jl_is_datatype (t ) && needs_uniquing (v ))
966+ if (jl_is_datatype (t ) && needs_uniquing (v , s -> query_cache ))
951967 immediate = 1 ;
952- if (jl_is_datatype_singleton ((jl_datatype_t * )t ) && needs_uniquing (v ))
968+ if (jl_is_datatype_singleton ((jl_datatype_t * )t ) && needs_uniquing (v , s -> query_cache ))
953969 immediate = 1 ;
954970 }
955971
@@ -1113,7 +1129,7 @@ static uintptr_t _backref_id(jl_serializer_state *s, jl_value_t *v, jl_array_t *
11131129
11141130static void record_uniquing (jl_serializer_state * s , jl_value_t * fld , uintptr_t offset ) JL_NOTSAFEPOINT
11151131{
1116- if (s -> incremental && jl_needs_serialization (s , fld ) && needs_uniquing (fld )) {
1132+ if (s -> incremental && jl_needs_serialization (s , fld ) && needs_uniquing (fld , s -> query_cache )) {
11171133 if (jl_is_datatype (fld ) || jl_is_datatype_singleton ((jl_datatype_t * )jl_typeof (fld )))
11181134 arraylist_push (& s -> uniquing_types , (void * )(uintptr_t )offset );
11191135 else if (jl_is_method_instance (fld ))
@@ -1297,7 +1313,7 @@ static void jl_write_values(jl_serializer_state *s) JL_GC_DISABLED
12971313 // write header
12981314 if (object_id_expected )
12991315 write_uint (f , jl_object_id (v ));
1300- if (s -> incremental && jl_needs_serialization (s , (jl_value_t * )t ) && needs_uniquing ((jl_value_t * )t ))
1316+ if (s -> incremental && jl_needs_serialization (s , (jl_value_t * )t ) && needs_uniquing ((jl_value_t * )t , s -> query_cache ))
13011317 arraylist_push (& s -> uniquing_types , (void * )(uintptr_t )(ios_pos (f )|1 ));
13021318 if (f == s -> const_data )
13031319 write_uint (s -> const_data , ((uintptr_t )t -> smalltag << 4 ) | GC_OLD_MARKED | GC_IN_IMAGE );
@@ -1308,7 +1324,7 @@ static void jl_write_values(jl_serializer_state *s) JL_GC_DISABLED
13081324 layout_table .items [item ] = (void * )(reloc_offset | (f == s -> const_data )); // store the inverse mapping of `serialization_order` (`id` => object-as-streampos)
13091325
13101326 if (s -> incremental ) {
1311- if (needs_uniquing (v )) {
1327+ if (needs_uniquing (v , s -> query_cache )) {
13121328 if (jl_is_method_instance (v )) {
13131329 assert (f == s -> s );
13141330 jl_method_instance_t * mi = (jl_method_instance_t * )v ;
@@ -1329,7 +1345,7 @@ static void jl_write_values(jl_serializer_state *s) JL_GC_DISABLED
13291345 assert (jl_is_datatype_singleton (t ) && "unreachable" );
13301346 }
13311347 }
1332- else if (needs_recaching (v )) {
1348+ else if (needs_recaching (v , s -> query_cache )) {
13331349 arraylist_push (jl_is_datatype (v ) ? & s -> fixup_types : & s -> fixup_objs , (void * )reloc_offset );
13341350 }
13351351 else if (jl_typetagis (v , jl_binding_type )) {
@@ -1731,7 +1747,7 @@ static void jl_write_values(jl_serializer_state *s) JL_GC_DISABLED
17311747 }
17321748 }
17331749 void * superidx = ptrhash_get (& serialization_order , dt -> super );
1734- if (s -> incremental && superidx != HT_NOTFOUND && (char * )superidx - 1 - (char * )HT_NOTFOUND > item && needs_uniquing ((jl_value_t * )dt -> super ))
1750+ if (s -> incremental && superidx != HT_NOTFOUND && (char * )superidx - 1 - (char * )HT_NOTFOUND > item && needs_uniquing ((jl_value_t * )dt -> super , s -> query_cache ))
17351751 arraylist_push (& s -> uniquing_super , dt -> super );
17361752 }
17371753 else if (jl_is_typename (v )) {
@@ -2540,7 +2556,8 @@ JL_DLLEXPORT jl_value_t *jl_as_global_root(jl_value_t *val, int insert)
25402556
25412557static void jl_prepare_serialization_data (jl_array_t * mod_array , jl_array_t * newly_inferred , uint64_t worklist_key ,
25422558 /* outputs */ jl_array_t * * extext_methods , jl_array_t * * new_ext_cis ,
2543- jl_array_t * * method_roots_list , jl_array_t * * ext_targets , jl_array_t * * edges )
2559+ jl_array_t * * method_roots_list , jl_array_t * * ext_targets , jl_array_t * * edges ,
2560+ jl_query_cache * query_cache )
25442561{
25452562 // extext_methods: [method1, ...], worklist-owned "extending external" methods added to functions owned by modules outside the worklist
25462563 // ext_targets: [invokesig1, callee1, matches1, ...] non-worklist callees of worklist-owned methods
@@ -2551,7 +2568,7 @@ static void jl_prepare_serialization_data(jl_array_t *mod_array, jl_array_t *new
25512568 assert (edges_map == NULL );
25522569
25532570 // Save the inferred code from newly inferred, external methods
2554- * new_ext_cis = queue_external_cis (newly_inferred );
2571+ * new_ext_cis = queue_external_cis (newly_inferred , query_cache );
25552572
25562573 // Collect method extensions and edges data
25572574 JL_GC_PUSH1 (& edges_map );
@@ -2590,7 +2607,8 @@ static void jl_prepare_serialization_data(jl_array_t *mod_array, jl_array_t *new
25902607static void jl_save_system_image_to_stream (ios_t * f , jl_array_t * mod_array ,
25912608 jl_array_t * worklist , jl_array_t * extext_methods ,
25922609 jl_array_t * new_ext_cis , jl_array_t * method_roots_list ,
2593- jl_array_t * ext_targets , jl_array_t * edges ) JL_GC_DISABLED
2610+ jl_array_t * ext_targets , jl_array_t * edges ,
2611+ jl_query_cache * query_cache ) JL_GC_DISABLED
25942612{
25952613 htable_new (& field_replace , 0 );
25962614 // strip metadata and IR when requested
@@ -2617,6 +2635,7 @@ static void jl_save_system_image_to_stream(ios_t *f, jl_array_t *mod_array,
26172635 ios_mem (& gvar_record , 0 );
26182636 ios_mem (& fptr_record , 0 );
26192637 jl_serializer_state s = {0 };
2638+ s .query_cache = query_cache ;
26202639 s .incremental = !(worklist == NULL );
26212640 s .s = & sysimg ;
26222641 s .const_data = & const_data ;
@@ -2947,12 +2966,15 @@ JL_DLLEXPORT void jl_create_system_image(void **_native_data, jl_array_t *workli
29472966 int64_t datastartpos = 0 ;
29482967 JL_GC_PUSH6 (& mod_array , & extext_methods , & new_ext_cis , & method_roots_list , & ext_targets , & edges );
29492968
2969+ jl_query_cache query_cache ;
2970+ init_query_cache (& query_cache );
2971+
29502972 if (worklist ) {
29512973 mod_array = jl_get_loaded_modules (); // __toplevel__ modules loaded in this session (from Base.loaded_modules_array)
29522974 // Generate _native_data`
29532975 if (_native_data != NULL ) {
29542976 jl_prepare_serialization_data (mod_array , newly_inferred , jl_worklist_key (worklist ),
2955- & extext_methods , & new_ext_cis , NULL , NULL , NULL );
2977+ & extext_methods , & new_ext_cis , NULL , NULL , NULL , & query_cache );
29562978 jl_precompile_toplevel_module = (jl_module_t * )jl_array_ptr_ref (worklist , jl_array_len (worklist )- 1 );
29572979 * _native_data = jl_precompile_worklist (worklist , extext_methods , new_ext_cis );
29582980 jl_precompile_toplevel_module = NULL ;
@@ -2981,7 +3003,7 @@ JL_DLLEXPORT void jl_create_system_image(void **_native_data, jl_array_t *workli
29813003 if (worklist ) {
29823004 htable_new (& relocatable_ext_cis , 0 );
29833005 jl_prepare_serialization_data (mod_array , newly_inferred , jl_worklist_key (worklist ),
2984- & extext_methods , & new_ext_cis , & method_roots_list , & ext_targets , & edges );
3006+ & extext_methods , & new_ext_cis , & method_roots_list , & ext_targets , & edges , & query_cache );
29853007 if (!emit_split ) {
29863008 write_int32 (f , 0 ); // No clone_targets
29873009 write_padding (f , LLT_ALIGN (ios_pos (f ), JL_CACHE_BYTE_ALIGNMENT ) - ios_pos (f ));
@@ -2993,7 +3015,7 @@ JL_DLLEXPORT void jl_create_system_image(void **_native_data, jl_array_t *workli
29933015 }
29943016 if (_native_data != NULL )
29953017 native_functions = * _native_data ;
2996- jl_save_system_image_to_stream (ff , mod_array , worklist , extext_methods , new_ext_cis , method_roots_list , ext_targets , edges );
3018+ jl_save_system_image_to_stream (ff , mod_array , worklist , extext_methods , new_ext_cis , method_roots_list , ext_targets , edges , & query_cache );
29973019 if (_native_data != NULL )
29983020 native_functions = NULL ;
29993021 if (worklist )
@@ -3024,6 +3046,8 @@ JL_DLLEXPORT void jl_create_system_image(void **_native_data, jl_array_t *workli
30243046 }
30253047 }
30263048
3049+ destroy_query_cache (& query_cache );
3050+
30273051 JL_GC_POP ();
30283052 * s = f ;
30293053 if (emit_split )
0 commit comments