@@ -295,7 +295,6 @@ static arraylist_t deser_sym;
295
295
static htable_t external_objects ;
296
296
297
297
static htable_t serialization_order ; // to break cycles, mark all objects that are serialized
298
- static htable_t unique_ready ; // as we serialize types, we need to know if all reachable objects are also already serialized. This tracks whether `immediate` has been set for all of them.
299
298
static htable_t nullptrs ;
300
299
// FIFO queue for objects to be serialized. Anything requiring fixup upon deserialization
301
300
// must be "toplevel" in this queue. For types, parameters and field types must appear
@@ -463,6 +462,7 @@ typedef struct {
463
462
arraylist_t relocs_list ; // a list of (location, target) pairs, see description at top
464
463
arraylist_t gctags_list ; // "
465
464
arraylist_t uniquing_types ; // a list of locations that reference types that must be de-duplicated
465
+ arraylist_t uniquing_super ; // a list of datatypes, used in super fields, that need to be marked in uniquing_types once they are reached, for handling unique-ing of them on deserialization
466
466
arraylist_t uniquing_objs ; // a list of locations that reference non-types that must be de-duplicated
467
467
arraylist_t fixup_types ; // a list of locations of types requiring (re)caching
468
468
arraylist_t fixup_objs ; // a list of locations of objects requiring (re)caching
@@ -726,14 +726,13 @@ static void jl_insert_into_serialization_queue(jl_serializer_state *s, jl_value_
726
726
{
727
727
jl_datatype_t * t = (jl_datatype_t * )jl_typeof (v );
728
728
jl_queue_for_serialization_ (s , (jl_value_t * )t , 1 , immediate );
729
+ const jl_datatype_layout_t * layout = t -> layout ;
729
730
730
731
if (!recursive )
731
732
goto done_fields ;
732
733
733
734
if (s -> incremental && jl_is_datatype (v ) && immediate ) {
734
735
jl_datatype_t * dt = (jl_datatype_t * )v ;
735
- // ensure super is queued (though possibly not yet handled, since it may have cycles)
736
- jl_queue_for_serialization_ (s , (jl_value_t * )dt -> super , 1 , 1 );
737
736
// ensure all type parameters are recached
738
737
jl_queue_for_serialization_ (s , (jl_value_t * )dt -> parameters , 1 , 1 );
739
738
jl_value_t * singleton = dt -> instance ;
@@ -743,7 +742,7 @@ static void jl_insert_into_serialization_queue(jl_serializer_state *s, jl_value_
743
742
// (it may get serialized from elsewhere though)
744
743
record_field_change (& dt -> instance , jl_nothing );
745
744
}
746
- immediate = 0 ; // do not handle remaining fields immediately (just field types remains)
745
+ goto done_fields ; // for now
747
746
}
748
747
if (s -> incremental && jl_is_method_instance (v )) {
749
748
jl_method_instance_t * mi = (jl_method_instance_t * )v ;
@@ -800,11 +799,9 @@ static void jl_insert_into_serialization_queue(jl_serializer_state *s, jl_value_
800
799
}
801
800
}
802
801
803
-
804
802
if (immediate ) // must be things that can be recursively handled, and valid as type parameters
805
803
assert (jl_is_immutable (t ) || jl_is_typevar (v ) || jl_is_symbol (v ) || jl_is_svec (v ));
806
804
807
- const jl_datatype_layout_t * layout = t -> layout ;
808
805
if (layout -> npointers == 0 ) {
809
806
// bitstypes do not require recursion
810
807
}
@@ -860,22 +857,35 @@ done_fields: ;
860
857
861
858
// We've encountered an item we need to cache
862
859
void * * bp = ptrhash_bp (& serialization_order , v );
863
- assert (* bp != (void * )(uintptr_t )-1 );
864
- if (s -> incremental ) {
865
- void * * bp2 = ptrhash_bp (& unique_ready , v );
866
- if (* bp2 == HT_NOTFOUND )
867
- assert (* bp == (void * )(uintptr_t )-2 );
868
- else if (* bp != (void * )(uintptr_t )-2 )
869
- return ;
870
- }
871
- else {
872
- assert (* bp == (void * )(uintptr_t )-2 );
873
- }
860
+ assert (* bp == (void * )(uintptr_t )-2 );
874
861
arraylist_push (& serialization_queue , (void * ) v );
875
862
size_t idx = serialization_queue .len - 1 ;
876
863
assert (serialization_queue .len < ((uintptr_t )1 << RELOC_TAG_OFFSET ) && "too many items to serialize" );
877
-
878
864
* bp = (void * )((char * )HT_NOTFOUND + 1 + idx );
865
+
866
+ // DataType is very unusual, in that some of the fields need to be pre-order, and some
867
+ // (notably super) must not be (even if `jl_queue_for_serialization_` would otherwise
868
+ // try to promote itself to be immediate)
869
+ if (s -> incremental && jl_is_datatype (v ) && immediate && recursive ) {
870
+ jl_datatype_t * dt = (jl_datatype_t * )v ;
871
+ void * * bp = ptrhash_bp (& serialization_order , (void * )dt -> super );
872
+ if (* bp != (void * )-2 ) {
873
+ // if super is already on the stack of things to handle when this returns, do
874
+ // not try to handle it now
875
+ jl_queue_for_serialization_ (s , (jl_value_t * )dt -> super , 1 , immediate );
876
+ }
877
+ immediate = 0 ;
878
+ char * data = (char * )jl_data_ptr (v );
879
+ size_t i , np = layout -> npointers ;
880
+ for (i = 0 ; i < np ; i ++ ) {
881
+ uint32_t ptr = jl_ptr_offset (t , i );
882
+ if (ptr * sizeof (jl_value_t * ) == offsetof(jl_datatype_t , super ))
883
+ continue ; // skip the super field, since it might not be quite validly ordered
884
+ int mutabl = 1 ;
885
+ jl_value_t * fld = get_replaceable_field (& ((jl_value_t * * )data )[ptr ], mutabl );
886
+ jl_queue_for_serialization_ (s , fld , 1 , immediate );
887
+ }
888
+ }
879
889
}
880
890
881
891
static void jl_queue_for_serialization_ (jl_serializer_state * s , jl_value_t * v , int recursive , int immediate ) JL_GC_DISABLED
@@ -894,28 +904,19 @@ static void jl_queue_for_serialization_(jl_serializer_state *s, jl_value_t *v, i
894
904
}
895
905
896
906
void * * bp = ptrhash_bp (& serialization_order , v );
897
- if (* bp == HT_NOTFOUND ) {
898
- * bp = (void * )(uintptr_t )(immediate ? -2 : -1 );
899
- }
900
- else {
901
- if (!s -> incremental || !immediate || !recursive )
902
- return ;
903
- void * * bp2 = ptrhash_bp (& unique_ready , v );
904
- if (* bp2 == HT_NOTFOUND )
905
- * bp2 = v ; // now is unique_ready
906
- else {
907
- assert (* bp != (void * )(uintptr_t )-1 );
908
- return ; // already was unique_ready
909
- }
910
- assert (* bp != (void * )(uintptr_t )-2 ); // should be unique_ready then
911
- if (* bp == (void * )(uintptr_t )-1 )
912
- * bp = (void * )(uintptr_t )-2 ; // now immediate
913
- }
907
+ assert (!immediate || * bp != (void * )(uintptr_t )-2 );
908
+ if (* bp == HT_NOTFOUND )
909
+ * bp = (void * )(uintptr_t )-1 ; // now enqueued
910
+ else if (!s -> incremental || !immediate || !recursive || * bp != (void * )(uintptr_t )-1 )
911
+ return ;
914
912
915
- if (immediate )
913
+ if (immediate ) {
914
+ * bp = (void * )(uintptr_t )-2 ; // now immediate
916
915
jl_insert_into_serialization_queue (s , v , recursive , immediate );
917
- else
916
+ }
917
+ else {
918
918
arraylist_push (& object_worklist , (void * )v );
919
+ }
919
920
}
920
921
921
922
// Do a pre-order traversal of the to-serialize worklist, in the identical order
@@ -1065,8 +1066,10 @@ static void record_uniquing(jl_serializer_state *s, jl_value_t *fld, uintptr_t o
1065
1066
if (s -> incremental && jl_needs_serialization (s , fld ) && needs_uniquing (fld )) {
1066
1067
if (jl_is_datatype (fld ) || jl_is_datatype_singleton ((jl_datatype_t * )jl_typeof (fld )))
1067
1068
arraylist_push (& s -> uniquing_types , (void * )(uintptr_t )offset );
1068
- else
1069
+ else if ( jl_is_method_instance ( fld ))
1069
1070
arraylist_push (& s -> uniquing_objs , (void * )(uintptr_t )offset );
1071
+ else
1072
+ assert (0 && "unknown object type with needs_uniquing set" );
1070
1073
}
1071
1074
}
1072
1075
@@ -1224,7 +1227,15 @@ static void jl_write_values(jl_serializer_state *s) JL_GC_DISABLED
1224
1227
write_pointerfield (s , (jl_value_t * )mi -> sparam_vals );
1225
1228
continue ;
1226
1229
}
1227
- else if (!jl_is_datatype (v )) {
1230
+ else if (jl_is_datatype (v )) {
1231
+ for (size_t i = 0 ; i < s -> uniquing_super .len ; i ++ ) {
1232
+ if (s -> uniquing_super .items [i ] == (void * )v ) {
1233
+ s -> uniquing_super .items [i ] = arraylist_pop (& s -> uniquing_super );
1234
+ arraylist_push (& s -> uniquing_types , (void * )(uintptr_t )(reloc_offset |3 ));
1235
+ }
1236
+ }
1237
+ }
1238
+ else {
1228
1239
assert (jl_is_datatype_singleton (t ) && "unreachable" );
1229
1240
}
1230
1241
}
@@ -1589,6 +1600,9 @@ static void jl_write_values(jl_serializer_state *s) JL_GC_DISABLED
1589
1600
ios_write (s -> const_data , (char * )& dyn , sizeof (jl_fielddescdyn_t ));
1590
1601
}
1591
1602
}
1603
+ void * superidx = ptrhash_get (& serialization_order , dt -> super );
1604
+ if (s -> incremental && superidx != HT_NOTFOUND && (char * )superidx - 1 - (char * )HT_NOTFOUND > item && needs_uniquing ((jl_value_t * )dt -> super ))
1605
+ arraylist_push (& s -> uniquing_super , dt -> super );
1592
1606
}
1593
1607
else if (jl_is_typename (v )) {
1594
1608
assert (f == s -> s );
@@ -1633,6 +1647,7 @@ static void jl_write_values(jl_serializer_state *s) JL_GC_DISABLED
1633
1647
}
1634
1648
}
1635
1649
}
1650
+ assert (s -> uniquing_super .len == 0 );
1636
1651
}
1637
1652
1638
1653
// In deserialization, create Symbols and set up the
@@ -2397,7 +2412,6 @@ static void jl_save_system_image_to_stream(ios_t *f, jl_array_t *mod_array,
2397
2412
ptrhash_put (& fptr_to_id , (void * )(uintptr_t )id_to_fptrs [i ], (void * )(i + 2 ));
2398
2413
}
2399
2414
htable_new (& serialization_order , 25000 );
2400
- htable_new (& unique_ready , 0 );
2401
2415
htable_new (& nullptrs , 0 );
2402
2416
arraylist_new (& object_worklist , 0 );
2403
2417
arraylist_new (& serialization_queue , 0 );
@@ -2420,6 +2434,7 @@ static void jl_save_system_image_to_stream(ios_t *f, jl_array_t *mod_array,
2420
2434
arraylist_new (& s .relocs_list , 0 );
2421
2435
arraylist_new (& s .gctags_list , 0 );
2422
2436
arraylist_new (& s .uniquing_types , 0 );
2437
+ arraylist_new (& s .uniquing_super , 0 );
2423
2438
arraylist_new (& s .uniquing_objs , 0 );
2424
2439
arraylist_new (& s .fixup_types , 0 );
2425
2440
arraylist_new (& s .fixup_objs , 0 );
@@ -2652,6 +2667,11 @@ static void jl_save_system_image_to_stream(ios_t *f, jl_array_t *mod_array,
2652
2667
arraylist_free (& object_worklist );
2653
2668
arraylist_free (& serialization_queue );
2654
2669
arraylist_free (& layout_table );
2670
+ arraylist_free (& s .uniquing_types );
2671
+ arraylist_free (& s .uniquing_super );
2672
+ arraylist_free (& s .uniquing_objs );
2673
+ arraylist_free (& s .fixup_types );
2674
+ arraylist_free (& s .fixup_objs );
2655
2675
arraylist_free (& s .ccallable_list );
2656
2676
arraylist_free (& s .relocs_list );
2657
2677
arraylist_free (& s .gctags_list );
@@ -2661,7 +2681,6 @@ static void jl_save_system_image_to_stream(ios_t *f, jl_array_t *mod_array,
2661
2681
if (worklist )
2662
2682
htable_free (& external_objects );
2663
2683
htable_free (& serialization_order );
2664
- htable_free (& unique_ready );
2665
2684
htable_free (& nullptrs );
2666
2685
htable_free (& symbol_table );
2667
2686
htable_free (& fptr_to_id );
@@ -3026,31 +3045,43 @@ static void jl_restore_system_image_from_stream_(ios_t *f, jl_image_t *image, jl
3026
3045
uintptr_t item = (uintptr_t )s .uniquing_types .items [i ];
3027
3046
// check whether we are operating on the typetag
3028
3047
// (needing to ignore GC bits) or a regular field
3029
- int tag = (item & 1 ) == 1 ;
3030
- // check whether this is a gvar index
3031
- int gvar = (item & 2 ) == 2 ;
3048
+ // and check whether this is a gvar index
3049
+ int tag = (item & 3 );
3032
3050
item &= ~(uintptr_t )3 ;
3033
3051
uintptr_t * pfld ;
3034
3052
jl_value_t * * obj , * newobj ;
3035
- if (gvar ) {
3053
+ if (tag == 3 ) {
3054
+ obj = (jl_value_t * * )(image_base + item );
3055
+ pfld = NULL ;
3056
+ for (size_t i = 0 ; i < delay_list .len ; i += 2 ) {
3057
+ if (obj == (jl_value_t * * )delay_list .items [i + 0 ]) {
3058
+ pfld = (uintptr_t * )delay_list .items [i + 1 ];
3059
+ delay_list .items [i + 1 ] = arraylist_pop (& delay_list );
3060
+ delay_list .items [i + 0 ] = arraylist_pop (& delay_list );
3061
+ break ;
3062
+ }
3063
+ }
3064
+ assert (pfld );
3065
+ }
3066
+ else if (tag == 2 ) {
3036
3067
if (image -> gvars_base == NULL )
3037
3068
continue ;
3038
3069
item >>= 2 ;
3039
3070
assert (item < s .gvar_record -> size / sizeof (reloc_t ));
3040
3071
pfld = sysimg_gvars (image -> gvars_base , image -> gvars_offsets , item );
3041
3072
obj = * (jl_value_t * * * )pfld ;
3042
- assert (tag == 0 );
3043
3073
}
3044
3074
else {
3045
3075
pfld = (uintptr_t * )(image_base + item );
3046
- if (tag )
3076
+ if (tag == 1 )
3047
3077
obj = (jl_value_t * * )jl_typeof (jl_valueof (pfld ));
3048
3078
else
3049
3079
obj = * (jl_value_t * * * )pfld ;
3050
3080
if ((char * )obj > (char * )pfld ) {
3081
+ // this must be the super field
3051
3082
assert (tag == 0 );
3052
- arraylist_push (& delay_list , pfld );
3053
3083
arraylist_push (& delay_list , obj );
3084
+ arraylist_push (& delay_list , pfld );
3054
3085
ptrhash_put (& new_dt_objs , (void * )obj , obj ); // mark obj as invalid
3055
3086
* pfld = (uintptr_t )NULL ;
3056
3087
continue ;
@@ -3100,25 +3131,14 @@ static void jl_restore_system_image_from_stream_(ios_t *f, jl_image_t *image, jl
3100
3131
assert (newobj != jl_nothing );
3101
3132
arraylist_push (& cleanup_list , (void * )obj );
3102
3133
}
3103
- if (tag )
3134
+ if (tag == 1 )
3104
3135
* pfld = (uintptr_t )newobj | GC_OLD | GC_IN_IMAGE ;
3105
3136
else
3106
3137
* pfld = (uintptr_t )newobj ;
3107
3138
assert (!(image_base < (char * )newobj && (char * )newobj <= image_base + sizeof_sysimg ));
3108
3139
assert (jl_typetagis (obj , otyp ));
3109
3140
}
3110
- // A few fields (reached via super) might be self-recursive. This is rare, but handle them now.
3111
- // They cannot be instances though, since the type must fully exist before the singleton field can be allocated
3112
- for (size_t i = 0 ; i < delay_list .len ; ) {
3113
- uintptr_t * pfld = (uintptr_t * )delay_list .items [i ++ ];
3114
- jl_value_t * * obj = (jl_value_t * * )delay_list .items [i ++ ];
3115
- assert (jl_is_datatype (obj ));
3116
- jl_datatype_t * dt = (jl_datatype_t * )obj [0 ];
3117
- assert (jl_is_datatype (dt ));
3118
- jl_value_t * newobj = (jl_value_t * )dt ;
3119
- * pfld = (uintptr_t )newobj ;
3120
- assert (!(image_base < (char * )newobj && (char * )newobj <= image_base + sizeof_sysimg ));
3121
- }
3141
+ assert (delay_list .len == 0 );
3122
3142
arraylist_free (& delay_list );
3123
3143
// now that all the fields of dt are assigned and unique, copy them into
3124
3144
// their final newdt memory location: this ensures we do not accidentally
@@ -3166,11 +3186,12 @@ static void jl_restore_system_image_from_stream_(ios_t *f, jl_image_t *image, jl
3166
3186
for (size_t i = 0 ; i < s .uniquing_objs .len ; i ++ ) {
3167
3187
uintptr_t item = (uintptr_t )s .uniquing_objs .items [i ];
3168
3188
// check whether this is a gvar index
3169
- int gvar = (item & 2 ) == 2 ;
3189
+ int tag = (item & 3 );
3190
+ assert (tag == 0 || tag == 2 );
3170
3191
item &= ~(uintptr_t )3 ;
3171
3192
uintptr_t * pfld ;
3172
3193
jl_value_t * * obj , * newobj ;
3173
- if (gvar ) {
3194
+ if (tag == 2 ) {
3174
3195
if (image -> gvars_base == NULL )
3175
3196
continue ;
3176
3197
item >>= 2 ;
0 commit comments