@@ -20,6 +20,32 @@ extern "C" {
20
20
21
21
#define JL_ARRAY_ALIGN (jl_value , nbytes ) LLT_ALIGN(jl_value, nbytes)
22
22
23
+ // this is a version of memcpy that preserves atomic memory ordering
24
+ // which makes it safe to use for objects that can contain memory references
25
+ // without risk of creating pointers out of thin air
26
+ void memmove_refs (void * * dstp , void * const * srcp , size_t n ) JL_NOTSAFEPOINT
27
+ {
28
+ size_t i ;
29
+ if (dstp < srcp || dstp > srcp + n ) {
30
+ for (i = 0 ; i < n ; i ++ ) {
31
+ jl_atomic_store_relaxed (dstp + i , jl_atomic_load_relaxed (srcp + i ));
32
+ }
33
+ }
34
+ else {
35
+ for (i = 0 ; i < n ; i ++ ) {
36
+ jl_atomic_store_relaxed (dstp + n - i - 1 , jl_atomic_load_relaxed (srcp + n - i - 1 ));
37
+ }
38
+ }
39
+ }
40
+
41
+ void memmove_safe (int hasptr , char * dst , const char * src , size_t nb ) JL_NOTSAFEPOINT
42
+ {
43
+ if (hasptr )
44
+ memmove_refs ((void * * )dst , (void * * )src , nb / sizeof (void * ));
45
+ else
46
+ memmove (dst , src , nb );
47
+ }
48
+
23
49
// array constructors ---------------------------------------------------------
24
50
char * jl_array_typetagdata (jl_array_t * a ) JL_NOTSAFEPOINT
25
51
{
@@ -542,10 +568,9 @@ JL_DLLEXPORT jl_value_t *jl_ptrarrayref(jl_array_t *a JL_PROPAGATES_ROOT, size_t
542
568
{
543
569
assert (i < jl_array_len (a ));
544
570
assert (a -> flags .ptrarray );
545
- jl_value_t * elt = (( jl_value_t * * )a -> data )[ i ] ;
546
- if (elt == NULL ) {
571
+ jl_value_t * elt = jl_atomic_load_relaxed ((( jl_value_t * * )a -> data ) + i ) ;
572
+ if (elt == NULL )
547
573
jl_throw (jl_undefref_exception );
548
- }
549
574
return elt ;
550
575
}
551
576
@@ -569,7 +594,7 @@ JL_DLLEXPORT jl_value_t *jl_arrayref(jl_array_t *a, size_t i)
569
594
JL_DLLEXPORT int jl_array_isassigned (jl_array_t * a , size_t i )
570
595
{
571
596
if (a -> flags .ptrarray ) {
572
- return (( jl_value_t * * )jl_array_data (a ))[ i ] != NULL ;
597
+ return jl_atomic_load_relaxed ((( jl_value_t * * )jl_array_data (a )) + i ) != NULL ;
573
598
}
574
599
else if (a -> flags .hasptr ) {
575
600
jl_datatype_t * eltype = (jl_datatype_t * )jl_tparam0 (jl_typeof (a ));
@@ -600,12 +625,18 @@ JL_DLLEXPORT void jl_arrayset(jl_array_t *a JL_ROOTING_ARGUMENT, jl_value_t *rhs
600
625
if (jl_is_datatype_singleton ((jl_datatype_t * )jl_typeof (rhs )))
601
626
return ;
602
627
}
603
- jl_assign_bits (& ((char * )a -> data )[i * a -> elsize ], rhs );
628
+ if (a -> flags .hasptr ) {
629
+ jl_fence_release ();
630
+ memmove_refs ((void * * )& ((char * )a -> data )[i * a -> elsize ], (void * * )rhs , a -> elsize / sizeof (void * ));
631
+ }
632
+ else {
633
+ jl_assign_bits (& ((char * )a -> data )[i * a -> elsize ], rhs );
634
+ }
604
635
if (a -> flags .hasptr )
605
636
jl_gc_multi_wb (jl_array_owner (a ), rhs );
606
637
}
607
638
else {
608
- (( jl_value_t * * )a -> data )[ i ] = rhs ;
639
+ jl_atomic_store_release ((( jl_value_t * * )a -> data ) + i , rhs ) ;
609
640
jl_gc_wb (jl_array_owner (a ), rhs );
610
641
}
611
642
}
@@ -615,7 +646,7 @@ JL_DLLEXPORT void jl_arrayunset(jl_array_t *a, size_t i)
615
646
if (i >= jl_array_len (a ))
616
647
jl_bounds_error_int ((jl_value_t * )a , i + 1 );
617
648
if (a -> flags .ptrarray )
618
- (( jl_value_t * * )a -> data )[ i ] = NULL ;
649
+ jl_atomic_store_release ((( jl_value_t * * )a -> data ) + i , NULL ) ;
619
650
else if (a -> flags .hasptr ) {
620
651
size_t elsize = a -> elsize ;
621
652
jl_assume (elsize >= sizeof (void * ) && elsize % sizeof (void * ) == 0 );
@@ -762,7 +793,7 @@ STATIC_INLINE void jl_array_grow_at_beg(jl_array_t *a, size_t idx, size_t inc,
762
793
if (isbitsunion ) newtypetagdata = typetagdata - inc ;
763
794
if (idx > 0 ) {
764
795
// inserting new elements after 1st element
765
- memmove ( newdata , data , idx * elsz );
796
+ memmove_safe ( a -> flags . hasptr , newdata , data , idx * elsz );
766
797
if (isbitsunion ) {
767
798
memmove (newtypetagdata , typetagdata , idx );
768
799
memset (newtypetagdata + idx , 0 , inc );
@@ -796,11 +827,11 @@ STATIC_INLINE void jl_array_grow_at_beg(jl_array_t *a, size_t idx, size_t inc,
796
827
// We could use memcpy if resizing allocates a new buffer,
797
828
// hopefully it's not a particularly important optimization.
798
829
if (idx > 0 && newdata < data ) {
799
- memmove ( newdata , data , nb1 );
830
+ memmove_safe ( a -> flags . hasptr , newdata , data , nb1 );
800
831
}
801
- memmove ( newdata + nbinc + nb1 , data + nb1 , n * elsz - nb1 );
832
+ memmove_safe ( a -> flags . hasptr , newdata + nbinc + nb1 , data + nb1 , n * elsz - nb1 );
802
833
if (idx > 0 && newdata > data ) {
803
- memmove ( newdata , data , nb1 );
834
+ memmove_safe ( a -> flags . hasptr , newdata , data , nb1 );
804
835
}
805
836
a -> offset = newoffset ;
806
837
}
@@ -810,16 +841,16 @@ STATIC_INLINE void jl_array_grow_at_beg(jl_array_t *a, size_t idx, size_t inc,
810
841
newdata = data - oldoffsnb + a -> offset * elsz ;
811
842
if (isbitsunion ) newtypetagdata = newdata + (a -> maxsize - a -> offset ) * elsz + a -> offset ;
812
843
if (idx > 0 && newdata < data ) {
813
- memmove ( newdata , data , nb1 );
844
+ memmove_safe ( a -> flags . hasptr , newdata , data , nb1 );
814
845
if (isbitsunion ) {
815
846
memmove (newtypetagdata , typetagdata , idx );
816
847
memset (newtypetagdata + idx , 0 , inc );
817
848
}
818
849
}
819
- memmove ( newdata + nbinc + nb1 , data + nb1 , n * elsz - nb1 );
850
+ memmove_safe ( a -> flags . hasptr , newdata + nbinc + nb1 , data + nb1 , n * elsz - nb1 );
820
851
if (isbitsunion ) memmove (newtypetagdata + idx + inc , typetagdata + idx , n - idx );
821
852
if (idx > 0 && newdata > data ) {
822
- memmove ( newdata , data , nb1 );
853
+ memmove_safe ( a -> flags . hasptr , newdata , data , nb1 );
823
854
if (isbitsunion ) {
824
855
memmove (newtypetagdata , typetagdata , idx );
825
856
memset (newtypetagdata + idx , 0 , inc );
@@ -891,7 +922,7 @@ STATIC_INLINE void jl_array_grow_at_end(jl_array_t *a, size_t idx,
891
922
memmove (newtypetagdata , typetagdata , idx );
892
923
memset (newtypetagdata + idx , 0 , inc );
893
924
}
894
- if (has_gap ) memmove ( newdata + nb1 + nbinc , newdata + nb1 , n * elsz - nb1 );
925
+ if (has_gap ) memmove_safe ( a -> flags . hasptr , newdata + nb1 + nbinc , newdata + nb1 , n * elsz - nb1 );
895
926
}
896
927
a -> data = data = newdata ;
897
928
}
@@ -901,7 +932,7 @@ STATIC_INLINE void jl_array_grow_at_end(jl_array_t *a, size_t idx,
901
932
memset (typetagdata + idx , 0 , inc );
902
933
}
903
934
size_t nb1 = idx * elsz ;
904
- memmove ( data + nb1 + inc * elsz , data + nb1 , n * elsz - nb1 );
935
+ memmove_safe ( a -> flags . hasptr , data + nb1 + inc * elsz , data + nb1 , n * elsz - nb1 );
905
936
}
906
937
else {
907
938
// there was enough room for requested growth already in a->maxsize
@@ -1036,12 +1067,12 @@ STATIC_INLINE void jl_array_del_at_beg(jl_array_t *a, size_t idx, size_t dec,
1036
1067
if (elsz == 1 && !isbitsunion )
1037
1068
nbtotal ++ ;
1038
1069
if (idx > 0 ) {
1039
- memmove ( newdata , olddata , nb1 );
1070
+ memmove_safe ( a -> flags . hasptr , newdata , olddata , nb1 );
1040
1071
if (isbitsunion ) memmove (newtypetagdata , typetagdata , idx );
1041
1072
}
1042
1073
// Move the rest of the data if the offset changed
1043
1074
if (newoffs != offset ) {
1044
- memmove ( newdata + nb1 , olddata + nb1 + nbdec , nbtotal - nb1 );
1075
+ memmove_safe ( a -> flags . hasptr , newdata + nb1 , olddata + nb1 + nbdec , nbtotal - nb1 );
1045
1076
if (isbitsunion ) memmove (newtypetagdata + idx , typetagdata + idx + dec , n - idx );
1046
1077
}
1047
1078
a -> data = newdata ;
@@ -1063,7 +1094,7 @@ STATIC_INLINE void jl_array_del_at_end(jl_array_t *a, size_t idx, size_t dec,
1063
1094
int isbitsunion = jl_array_isbitsunion (a );
1064
1095
size_t last = idx + dec ;
1065
1096
if (n > last ) {
1066
- memmove ( data + idx * elsz , data + last * elsz , (n - last ) * elsz );
1097
+ memmove_safe ( a -> flags . hasptr , data + idx * elsz , data + last * elsz , (n - last ) * elsz );
1067
1098
if (isbitsunion ) {
1068
1099
char * typetagdata = jl_array_typetagdata (a );
1069
1100
memmove (typetagdata + idx , typetagdata + last , n - last );
@@ -1161,14 +1192,14 @@ JL_DLLEXPORT jl_array_t *jl_array_copy(jl_array_t *ary)
1161
1192
}
1162
1193
1163
1194
// Copy element by element until we hit a young object, at which point
1164
- // we can continue using `memmove`.
1195
+ // we can finish by using `memmove`.
1165
1196
static NOINLINE ssize_t jl_array_ptr_copy_forward (jl_value_t * owner ,
1166
1197
void * * src_p , void * * dest_p ,
1167
1198
ssize_t n )
1168
1199
{
1169
1200
for (ssize_t i = 0 ; i < n ; i ++ ) {
1170
- void * val = src_p [ i ] ;
1171
- dest_p [ i ] = val ;
1201
+ void * val = jl_atomic_load_relaxed ( src_p + i ) ;
1202
+ jl_atomic_store_relaxed ( dest_p + i , val ) ;
1172
1203
// `val` is young or old-unmarked
1173
1204
if (val && !(jl_astaggedvalue (val )-> bits .gc & GC_MARKED )) {
1174
1205
jl_gc_queue_root (owner );
@@ -1183,8 +1214,8 @@ static NOINLINE ssize_t jl_array_ptr_copy_backward(jl_value_t *owner,
1183
1214
ssize_t n )
1184
1215
{
1185
1216
for (ssize_t i = 0 ; i < n ; i ++ ) {
1186
- void * val = src_p [ n - i - 1 ] ;
1187
- dest_p [ n - i - 1 ] = val ;
1217
+ void * val = jl_atomic_load_relaxed ( src_p + n - i - 1 ) ;
1218
+ jl_atomic_store_relaxed ( dest_p + n - i - 1 , val ) ;
1188
1219
// `val` is young or old-unmarked
1189
1220
if (val && !(jl_astaggedvalue (val )-> bits .gc & GC_MARKED )) {
1190
1221
jl_gc_queue_root (owner );
@@ -1200,6 +1231,7 @@ JL_DLLEXPORT void jl_array_ptr_copy(jl_array_t *dest, void **dest_p,
1200
1231
{
1201
1232
assert (dest -> flags .ptrarray && src -> flags .ptrarray );
1202
1233
jl_value_t * owner = jl_array_owner (dest );
1234
+ jl_fence_release (); // ensure contents of src are visible on other processors
1203
1235
// Destination is old and doesn't refer to any young object
1204
1236
if (__unlikely (jl_astaggedvalue (owner )-> bits .gc == GC_OLD_MARKED )) {
1205
1237
jl_value_t * src_owner = jl_array_owner (src );
@@ -1218,7 +1250,7 @@ JL_DLLEXPORT void jl_array_ptr_copy(jl_array_t *dest, void **dest_p,
1218
1250
n -= done ;
1219
1251
}
1220
1252
}
1221
- memmove (dest_p , src_p , n * sizeof ( void * ) );
1253
+ memmove_refs (dest_p , src_p , n );
1222
1254
}
1223
1255
1224
1256
JL_DLLEXPORT void jl_array_ptr_1d_push (jl_array_t * a , jl_value_t * item )
0 commit comments