@@ -90,6 +90,22 @@ static const size_t WORLD_AGE_REVALIDATION_SENTINEL = 0x1;
90
90
JL_DLLEXPORT size_t jl_require_world = ~(size_t )0 ;
91
91
JL_DLLEXPORT _Atomic(size_t ) jl_first_image_replacement_world = ~(size_t )0 ;
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
@@ -552,6 +568,7 @@ typedef struct {
552
568
jl_array_t * method_roots_list ;
553
569
htable_t method_roots_index ;
554
570
uint64_t worklist_key ;
571
+ jl_query_cache * query_cache ;
555
572
jl_ptls_t ptls ;
556
573
jl_image_t * image ;
557
574
int8_t incremental ;
@@ -675,14 +692,13 @@ static int jl_needs_serialization(jl_serializer_state *s, jl_value_t *v) JL_NOTS
675
692
return 1 ;
676
693
}
677
694
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
680
696
{
681
697
if (jl_is_method_instance (v )) {
682
698
jl_method_instance_t * mi = (jl_method_instance_t * )v ;
683
699
jl_value_t * m = mi -> def .value ;
684
700
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 );
686
702
}
687
703
if (jl_is_binding (v )) {
688
704
jl_globalref_t * gr = ((jl_binding_t * )v )-> globalref ;
@@ -697,24 +713,24 @@ static int caching_tag(jl_value_t *v) JL_NOTSAFEPOINT
697
713
if (jl_is_tuple_type (dt ) ? !dt -> isconcretetype : dt -> hasfreetypevars )
698
714
return 0 ; // aka !is_cacheable from jltypes.c
699
715
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 );
701
717
}
702
718
jl_value_t * dtv = jl_typeof (v );
703
719
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
705
721
}
706
722
return 0 ;
707
723
}
708
724
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
710
726
{
711
- return caching_tag (v ) == 2 ;
727
+ return caching_tag (v , query_cache ) == 2 ;
712
728
}
713
729
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
715
731
{
716
732
assert (!jl_object_in_image (v ));
717
- return caching_tag (v ) == 1 ;
733
+ return caching_tag (v , query_cache ) == 1 ;
718
734
}
719
735
720
736
static void record_field_change (jl_value_t * * addr , jl_value_t * newval ) JL_NOTSAFEPOINT
@@ -839,7 +855,7 @@ static void jl_insert_into_serialization_queue(jl_serializer_state *s, jl_value_
839
855
jl_datatype_t * dt = (jl_datatype_t * )v ;
840
856
// ensure all type parameters are recached
841
857
jl_queue_for_serialization_ (s , (jl_value_t * )dt -> parameters , 1 , 1 );
842
- if (jl_is_datatype_singleton (dt ) && needs_uniquing (dt -> instance )) {
858
+ if (jl_is_datatype_singleton (dt ) && needs_uniquing (dt -> instance , s -> query_cache )) {
843
859
assert (jl_needs_serialization (s , dt -> instance )); // should be true, since we visited dt
844
860
// do not visit dt->instance for our template object as it leads to unwanted cycles here
845
861
// (it may get serialized from elsewhere though)
@@ -850,7 +866,7 @@ static void jl_insert_into_serialization_queue(jl_serializer_state *s, jl_value_
850
866
if (s -> incremental && jl_is_method_instance (v )) {
851
867
jl_method_instance_t * mi = (jl_method_instance_t * )v ;
852
868
jl_value_t * def = mi -> def .value ;
853
- if (needs_uniquing (v )) {
869
+ if (needs_uniquing (v , s -> query_cache )) {
854
870
// we only need 3 specific fields of this (the rest are not used)
855
871
jl_queue_for_serialization (s , mi -> def .value );
856
872
jl_queue_for_serialization (s , mi -> specTypes );
@@ -865,7 +881,7 @@ static void jl_insert_into_serialization_queue(jl_serializer_state *s, jl_value_
865
881
record_field_change ((jl_value_t * * )& mi -> cache , NULL );
866
882
}
867
883
else {
868
- assert (!needs_recaching (v ));
884
+ assert (!needs_recaching (v , s -> query_cache ));
869
885
}
870
886
// n.b. opaque closures cannot be inspected and relied upon like a
871
887
// normal method since they can get improperly introduced by generated
@@ -875,7 +891,7 @@ static void jl_insert_into_serialization_queue(jl_serializer_state *s, jl_value_
875
891
// error now.
876
892
}
877
893
if (s -> incremental && jl_is_binding (v )) {
878
- if (needs_uniquing (v )) {
894
+ if (needs_uniquing (v , s -> query_cache )) {
879
895
jl_binding_t * b = (jl_binding_t * )v ;
880
896
jl_queue_for_serialization (s , b -> globalref -> mod );
881
897
jl_queue_for_serialization (s , b -> globalref -> name );
@@ -1102,9 +1118,9 @@ static void jl_queue_for_serialization_(jl_serializer_state *s, jl_value_t *v, i
1102
1118
// Items that require postorder traversal must visit their children prior to insertion into
1103
1119
// the worklist/serialization_order (and also before their first use)
1104
1120
if (s -> incremental && !immediate ) {
1105
- if (jl_is_datatype (t ) && needs_uniquing (v ))
1121
+ if (jl_is_datatype (t ) && needs_uniquing (v , s -> query_cache ))
1106
1122
immediate = 1 ;
1107
- 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 ))
1108
1124
immediate = 1 ;
1109
1125
}
1110
1126
@@ -1267,7 +1283,7 @@ static uintptr_t _backref_id(jl_serializer_state *s, jl_value_t *v, jl_array_t *
1267
1283
1268
1284
static void record_uniquing (jl_serializer_state * s , jl_value_t * fld , uintptr_t offset ) JL_NOTSAFEPOINT
1269
1285
{
1270
- 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 )) {
1271
1287
if (jl_is_datatype (fld ) || jl_is_datatype_singleton ((jl_datatype_t * )jl_typeof (fld )))
1272
1288
arraylist_push (& s -> uniquing_types , (void * )(uintptr_t )offset );
1273
1289
else if (jl_is_method_instance (fld ) || jl_is_binding (fld ))
@@ -1491,7 +1507,7 @@ static void jl_write_values(jl_serializer_state *s) JL_GC_DISABLED
1491
1507
// write header
1492
1508
if (object_id_expected )
1493
1509
write_uint (f , jl_object_id (v ));
1494
- 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 ))
1495
1511
arraylist_push (& s -> uniquing_types , (void * )(uintptr_t )(ios_pos (f )|1 ));
1496
1512
if (f == s -> const_data )
1497
1513
write_uint (s -> const_data , ((uintptr_t )t -> smalltag << 4 ) | GC_OLD_MARKED | GC_IN_IMAGE );
@@ -1502,7 +1518,7 @@ static void jl_write_values(jl_serializer_state *s) JL_GC_DISABLED
1502
1518
layout_table .items [item ] = (void * )(reloc_offset | (f == s -> const_data )); // store the inverse mapping of `serialization_order` (`id` => object-as-streampos)
1503
1519
1504
1520
if (s -> incremental ) {
1505
- if (needs_uniquing (v )) {
1521
+ if (needs_uniquing (v , s -> query_cache )) {
1506
1522
if (jl_typetagis (v , jl_binding_type )) {
1507
1523
jl_binding_t * b = (jl_binding_t * )v ;
1508
1524
if (b -> globalref == NULL )
@@ -1531,7 +1547,7 @@ static void jl_write_values(jl_serializer_state *s) JL_GC_DISABLED
1531
1547
assert (jl_is_datatype_singleton (t ) && "unreachable" );
1532
1548
}
1533
1549
}
1534
- else if (needs_recaching (v )) {
1550
+ else if (needs_recaching (v , s -> query_cache )) {
1535
1551
arraylist_push (jl_is_datatype (v ) ? & s -> fixup_types : & s -> fixup_objs , (void * )reloc_offset );
1536
1552
}
1537
1553
}
@@ -1964,7 +1980,7 @@ static void jl_write_values(jl_serializer_state *s) JL_GC_DISABLED
1964
1980
}
1965
1981
}
1966
1982
void * superidx = ptrhash_get (& serialization_order , dt -> super );
1967
- 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 ))
1968
1984
arraylist_push (& s -> uniquing_super , dt -> super );
1969
1985
}
1970
1986
else if (jl_is_typename (v )) {
@@ -2875,13 +2891,14 @@ JL_DLLEXPORT jl_value_t *jl_as_global_root(jl_value_t *val, int insert)
2875
2891
static void jl_prepare_serialization_data (jl_array_t * mod_array , jl_array_t * newly_inferred ,
2876
2892
/* outputs */ jl_array_t * * extext_methods JL_REQUIRE_ROOTED_SLOT ,
2877
2893
jl_array_t * * new_ext_cis JL_REQUIRE_ROOTED_SLOT ,
2878
- jl_array_t * * edges JL_REQUIRE_ROOTED_SLOT )
2894
+ jl_array_t * * edges JL_REQUIRE_ROOTED_SLOT ,
2895
+ jl_query_cache * query_cache )
2879
2896
{
2880
2897
// extext_methods: [method1, ...], worklist-owned "extending external" methods added to functions owned by modules outside the worklist
2881
2898
// edges: [caller1, ext_targets, ...] for worklist-owned methods calling external methods
2882
2899
2883
2900
// Save the inferred code from newly inferred, external methods
2884
- * new_ext_cis = queue_external_cis (newly_inferred );
2901
+ * new_ext_cis = queue_external_cis (newly_inferred , query_cache );
2885
2902
2886
2903
// Collect method extensions and edges data
2887
2904
* extext_methods = jl_alloc_vec_any (0 );
@@ -2911,7 +2928,8 @@ static void jl_prepare_serialization_data(jl_array_t *mod_array, jl_array_t *new
2911
2928
// In addition to the system image (where `worklist = NULL`), this can also save incremental images with external linkage
2912
2929
static void jl_save_system_image_to_stream (ios_t * f , jl_array_t * mod_array ,
2913
2930
jl_array_t * worklist , jl_array_t * extext_methods ,
2914
- 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 )
2915
2933
{
2916
2934
htable_new (& field_replace , 0 );
2917
2935
htable_new (& bits_replace , 0 );
@@ -3018,6 +3036,7 @@ static void jl_save_system_image_to_stream(ios_t *f, jl_array_t *mod_array,
3018
3036
ios_mem (& gvar_record , 0 );
3019
3037
ios_mem (& fptr_record , 0 );
3020
3038
jl_serializer_state s = {0 };
3039
+ s .query_cache = query_cache ;
3021
3040
s .incremental = !(worklist == NULL );
3022
3041
s .s = & sysimg ;
3023
3042
s .const_data = & const_data ;
@@ -3375,11 +3394,14 @@ JL_DLLEXPORT void jl_create_system_image(void **_native_data, jl_array_t *workli
3375
3394
int64_t datastartpos = 0 ;
3376
3395
JL_GC_PUSH4 (& mod_array , & extext_methods , & new_ext_cis , & edges );
3377
3396
3397
+ jl_query_cache query_cache ;
3398
+ init_query_cache (& query_cache );
3399
+
3378
3400
if (worklist ) {
3379
3401
mod_array = jl_get_loaded_modules (); // __toplevel__ modules loaded in this session (from Base.loaded_modules_array)
3380
3402
// Generate _native_data`
3381
3403
if (_native_data != NULL ) {
3382
- 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 );
3383
3405
jl_precompile_toplevel_module = (jl_module_t * )jl_array_ptr_ref (worklist , jl_array_len (worklist )- 1 );
3384
3406
* _native_data = jl_precompile_worklist (worklist , extext_methods , new_ext_cis );
3385
3407
jl_precompile_toplevel_module = NULL ;
@@ -3410,7 +3432,7 @@ JL_DLLEXPORT void jl_create_system_image(void **_native_data, jl_array_t *workli
3410
3432
assert ((ct -> reentrant_timing & 0b1110 ) == 0 );
3411
3433
ct -> reentrant_timing |= 0b1000 ;
3412
3434
if (worklist ) {
3413
- 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 );
3414
3436
if (!emit_split ) {
3415
3437
write_int32 (f , 0 ); // No clone_targets
3416
3438
write_padding (f , LLT_ALIGN (ios_pos (f ), JL_CACHE_BYTE_ALIGNMENT ) - ios_pos (f ));
@@ -3422,7 +3444,7 @@ JL_DLLEXPORT void jl_create_system_image(void **_native_data, jl_array_t *workli
3422
3444
}
3423
3445
if (_native_data != NULL )
3424
3446
native_functions = * _native_data ;
3425
- 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 );
3426
3448
if (_native_data != NULL )
3427
3449
native_functions = NULL ;
3428
3450
// make sure we don't run any Julia code concurrently before this point
@@ -3451,6 +3473,8 @@ JL_DLLEXPORT void jl_create_system_image(void **_native_data, jl_array_t *workli
3451
3473
}
3452
3474
}
3453
3475
3476
+ destroy_query_cache (& query_cache );
3477
+
3454
3478
JL_GC_POP ();
3455
3479
* s = f ;
3456
3480
if (emit_split )
0 commit comments