@@ -90,6 +90,22 @@ External links:
90
90
91
91
static const size_t WORLD_AGE_REVALIDATION_SENTINEL = 0x1 ;
92
92
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
+
93
109
#include "staticdata_utils.c"
94
110
#include "precompile_utils.c"
95
111
@@ -512,6 +528,7 @@ typedef struct {
512
528
jl_array_t * link_ids_gctags ;
513
529
jl_array_t * link_ids_gvars ;
514
530
jl_array_t * link_ids_external_fnvars ;
531
+ jl_query_cache * query_cache ;
515
532
jl_ptls_t ptls ;
516
533
// Set (implemented has a hasmap of MethodInstances to themselves) of which MethodInstances have (forward) edges
517
534
// to other MethodInstances.
@@ -658,38 +675,37 @@ static int jl_needs_serialization(jl_serializer_state *s, jl_value_t *v) JL_NOTS
658
675
return 1 ;
659
676
}
660
677
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
663
679
{
664
680
if (jl_is_method_instance (v )) {
665
681
jl_method_instance_t * mi = (jl_method_instance_t * )v ;
666
682
jl_value_t * m = mi -> def .value ;
667
683
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 );
669
685
}
670
686
if (jl_is_datatype (v )) {
671
687
jl_datatype_t * dt = (jl_datatype_t * )v ;
672
688
if (jl_is_tuple_type (dt ) ? !dt -> isconcretetype : dt -> hasfreetypevars )
673
689
return 0 ; // aka !is_cacheable from jltypes.c
674
690
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 );
676
692
}
677
693
jl_value_t * dtv = jl_typeof (v );
678
694
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
680
696
}
681
697
return 0 ;
682
698
}
683
699
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
685
701
{
686
- return caching_tag (v ) == 2 ;
702
+ return caching_tag (v , query_cache ) == 2 ;
687
703
}
688
704
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
690
706
{
691
707
assert (!jl_object_in_image (v ));
692
- return caching_tag (v ) == 1 ;
708
+ return caching_tag (v , query_cache ) == 1 ;
693
709
}
694
710
695
711
static 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_
774
790
jl_datatype_t * dt = (jl_datatype_t * )v ;
775
791
// ensure all type parameters are recached
776
792
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 )) {
778
794
assert (jl_needs_serialization (s , dt -> instance )); // should be true, since we visited dt
779
795
// do not visit dt->instance for our template object as it leads to unwanted cycles here
780
796
// (it may get serialized from elsewhere though)
@@ -785,7 +801,7 @@ static void jl_insert_into_serialization_queue(jl_serializer_state *s, jl_value_
785
801
if (s -> incremental && jl_is_method_instance (v )) {
786
802
jl_method_instance_t * mi = (jl_method_instance_t * )v ;
787
803
jl_value_t * def = mi -> def .value ;
788
- if (needs_uniquing (v )) {
804
+ if (needs_uniquing (v , s -> query_cache )) {
789
805
// we only need 3 specific fields of this (the rest are not used)
790
806
jl_queue_for_serialization (s , mi -> def .value );
791
807
jl_queue_for_serialization (s , mi -> specTypes );
@@ -801,7 +817,7 @@ static void jl_insert_into_serialization_queue(jl_serializer_state *s, jl_value_
801
817
record_field_change ((jl_value_t * * )& mi -> cache , NULL );
802
818
}
803
819
else {
804
- assert (!needs_recaching (v ));
820
+ assert (!needs_recaching (v , s -> query_cache ));
805
821
}
806
822
// n.b. opaque closures cannot be inspected and relied upon like a
807
823
// 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
947
963
// Items that require postorder traversal must visit their children prior to insertion into
948
964
// the worklist/serialization_order (and also before their first use)
949
965
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 ))
951
967
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 ))
953
969
immediate = 1 ;
954
970
}
955
971
@@ -1113,7 +1129,7 @@ static uintptr_t _backref_id(jl_serializer_state *s, jl_value_t *v, jl_array_t *
1113
1129
1114
1130
static void record_uniquing (jl_serializer_state * s , jl_value_t * fld , uintptr_t offset ) JL_NOTSAFEPOINT
1115
1131
{
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 )) {
1117
1133
if (jl_is_datatype (fld ) || jl_is_datatype_singleton ((jl_datatype_t * )jl_typeof (fld )))
1118
1134
arraylist_push (& s -> uniquing_types , (void * )(uintptr_t )offset );
1119
1135
else if (jl_is_method_instance (fld ))
@@ -1297,7 +1313,7 @@ static void jl_write_values(jl_serializer_state *s) JL_GC_DISABLED
1297
1313
// write header
1298
1314
if (object_id_expected )
1299
1315
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 ))
1301
1317
arraylist_push (& s -> uniquing_types , (void * )(uintptr_t )(ios_pos (f )|1 ));
1302
1318
if (f == s -> const_data )
1303
1319
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
1308
1324
layout_table .items [item ] = (void * )(reloc_offset | (f == s -> const_data )); // store the inverse mapping of `serialization_order` (`id` => object-as-streampos)
1309
1325
1310
1326
if (s -> incremental ) {
1311
- if (needs_uniquing (v )) {
1327
+ if (needs_uniquing (v , s -> query_cache )) {
1312
1328
if (jl_is_method_instance (v )) {
1313
1329
assert (f == s -> s );
1314
1330
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
1329
1345
assert (jl_is_datatype_singleton (t ) && "unreachable" );
1330
1346
}
1331
1347
}
1332
- else if (needs_recaching (v )) {
1348
+ else if (needs_recaching (v , s -> query_cache )) {
1333
1349
arraylist_push (jl_is_datatype (v ) ? & s -> fixup_types : & s -> fixup_objs , (void * )reloc_offset );
1334
1350
}
1335
1351
else if (jl_typetagis (v , jl_binding_type )) {
@@ -1731,7 +1747,7 @@ static void jl_write_values(jl_serializer_state *s) JL_GC_DISABLED
1731
1747
}
1732
1748
}
1733
1749
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 ))
1735
1751
arraylist_push (& s -> uniquing_super , dt -> super );
1736
1752
}
1737
1753
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)
2540
2556
2541
2557
static void jl_prepare_serialization_data (jl_array_t * mod_array , jl_array_t * newly_inferred , uint64_t worklist_key ,
2542
2558
/* 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 )
2544
2561
{
2545
2562
// extext_methods: [method1, ...], worklist-owned "extending external" methods added to functions owned by modules outside the worklist
2546
2563
// 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
2551
2568
assert (edges_map == NULL );
2552
2569
2553
2570
// 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 );
2555
2572
2556
2573
// Collect method extensions and edges data
2557
2574
JL_GC_PUSH1 (& edges_map );
@@ -2590,7 +2607,8 @@ static void jl_prepare_serialization_data(jl_array_t *mod_array, jl_array_t *new
2590
2607
static void jl_save_system_image_to_stream (ios_t * f , jl_array_t * mod_array ,
2591
2608
jl_array_t * worklist , jl_array_t * extext_methods ,
2592
2609
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
2594
2612
{
2595
2613
htable_new (& field_replace , 0 );
2596
2614
// 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,
2617
2635
ios_mem (& gvar_record , 0 );
2618
2636
ios_mem (& fptr_record , 0 );
2619
2637
jl_serializer_state s = {0 };
2638
+ s .query_cache = query_cache ;
2620
2639
s .incremental = !(worklist == NULL );
2621
2640
s .s = & sysimg ;
2622
2641
s .const_data = & const_data ;
@@ -2947,12 +2966,15 @@ JL_DLLEXPORT void jl_create_system_image(void **_native_data, jl_array_t *workli
2947
2966
int64_t datastartpos = 0 ;
2948
2967
JL_GC_PUSH6 (& mod_array , & extext_methods , & new_ext_cis , & method_roots_list , & ext_targets , & edges );
2949
2968
2969
+ jl_query_cache query_cache ;
2970
+ init_query_cache (& query_cache );
2971
+
2950
2972
if (worklist ) {
2951
2973
mod_array = jl_get_loaded_modules (); // __toplevel__ modules loaded in this session (from Base.loaded_modules_array)
2952
2974
// Generate _native_data`
2953
2975
if (_native_data != NULL ) {
2954
2976
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 );
2956
2978
jl_precompile_toplevel_module = (jl_module_t * )jl_array_ptr_ref (worklist , jl_array_len (worklist )- 1 );
2957
2979
* _native_data = jl_precompile_worklist (worklist , extext_methods , new_ext_cis );
2958
2980
jl_precompile_toplevel_module = NULL ;
@@ -2981,7 +3003,7 @@ JL_DLLEXPORT void jl_create_system_image(void **_native_data, jl_array_t *workli
2981
3003
if (worklist ) {
2982
3004
htable_new (& relocatable_ext_cis , 0 );
2983
3005
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 );
2985
3007
if (!emit_split ) {
2986
3008
write_int32 (f , 0 ); // No clone_targets
2987
3009
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
2993
3015
}
2994
3016
if (_native_data != NULL )
2995
3017
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 );
2997
3019
if (_native_data != NULL )
2998
3020
native_functions = NULL ;
2999
3021
if (worklist )
@@ -3024,6 +3046,8 @@ JL_DLLEXPORT void jl_create_system_image(void **_native_data, jl_array_t *workli
3024
3046
}
3025
3047
}
3026
3048
3049
+ destroy_query_cache (& query_cache );
3050
+
3027
3051
JL_GC_POP ();
3028
3052
* s = f ;
3029
3053
if (emit_split )
0 commit comments