@@ -220,6 +220,10 @@ pub struct RangeSet(Vec<(Size, Size)>);
220
220
221
221
impl RangeSet {
222
222
fn add_range ( & mut self , offset : Size , size : Size ) {
223
+ if size. bytes ( ) == 0 {
224
+ // No need to track empty ranges.
225
+ return ;
226
+ }
223
227
let v = & mut self . 0 ;
224
228
// We scan for a partition point where the left partition is all the elements that end
225
229
// strictly before we start. Those are elements that are too "low" to merge with us.
@@ -938,42 +942,53 @@ impl<'rt, 'tcx, M: Machine<'tcx>> ValidityVisitor<'rt, 'tcx, M> {
938
942
let layout_cx = LayoutCx { tcx : * ecx. tcx , param_env : ecx. param_env } ;
939
943
return M :: cached_union_data_range ( ecx, layout. ty , || {
940
944
let mut out = RangeSet ( Vec :: new ( ) ) ;
941
- union_data_range_ ( & layout_cx, layout, Size :: ZERO , & mut out) ;
945
+ union_data_range_uncached ( & layout_cx, layout, Size :: ZERO , & mut out) ;
942
946
out
943
947
} ) ;
944
948
945
949
/// Helper for recursive traversal: add data ranges of the given type to `out`.
946
- fn union_data_range_ < ' tcx > (
950
+ fn union_data_range_uncached < ' tcx > (
947
951
cx : & LayoutCx < ' tcx , TyCtxt < ' tcx > > ,
948
952
layout : TyAndLayout < ' tcx > ,
949
953
base_offset : Size ,
950
954
out : & mut RangeSet ,
951
955
) {
956
+ // If this is a ZST, we don't contain any data. In particular, this helps us to quickly
957
+ // skip over huge arrays of ZST.
958
+ if layout. is_zst ( ) {
959
+ return ;
960
+ }
952
961
// Just recursively add all the fields of everything to the output.
953
962
match & layout. fields {
954
963
FieldsShape :: Primitive => {
955
964
out. add_range ( base_offset, layout. size ) ;
956
965
}
957
966
& FieldsShape :: Union ( fields) => {
958
- // Currently, all fields start at offset 0.
967
+ // Currently, all fields start at offset 0 (relative to `base_offset`) .
959
968
for field in 0 ..fields. get ( ) {
960
969
let field = layout. field ( cx, field) ;
961
- union_data_range_ ( cx, field, base_offset, out) ;
970
+ union_data_range_uncached ( cx, field, base_offset, out) ;
962
971
}
963
972
}
964
973
& FieldsShape :: Array { stride, count } => {
965
974
let elem = layout. field ( cx, 0 ) ;
966
- for idx in 0 ..count {
967
- // This repeats the same computation for every array elements... but the alternative
968
- // is to allocate temporary storage for a dedicated `out` set for the array element,
969
- // and replicating that N times. Is that better?
970
- union_data_range_ ( cx, elem, base_offset + idx * stride, out) ;
975
+
976
+ // Fast-path for large arrays of simple types that do not contain any padding.
977
+ if elem. abi . is_scalar ( ) {
978
+ out. add_range ( base_offset, elem. size * count) ;
979
+ } else {
980
+ for idx in 0 ..count {
981
+ // This repeats the same computation for every array element... but the alternative
982
+ // is to allocate temporary storage for a dedicated `out` set for the array element,
983
+ // and replicating that N times. Is that better?
984
+ union_data_range_uncached ( cx, elem, base_offset + idx * stride, out) ;
985
+ }
971
986
}
972
987
}
973
988
FieldsShape :: Arbitrary { offsets, .. } => {
974
989
for ( field, & offset) in offsets. iter_enumerated ( ) {
975
990
let field = layout. field ( cx, field. as_usize ( ) ) ;
976
- union_data_range_ ( cx, field, base_offset + offset, out) ;
991
+ union_data_range_uncached ( cx, field, base_offset + offset, out) ;
977
992
}
978
993
}
979
994
}
@@ -985,7 +1000,7 @@ impl<'rt, 'tcx, M: Machine<'tcx>> ValidityVisitor<'rt, 'tcx, M> {
985
1000
Variants :: Multiple { variants, .. } => {
986
1001
for variant in variants. indices ( ) {
987
1002
let variant = layout. for_variant ( cx, variant) ;
988
- union_data_range_ ( cx, variant, base_offset, out) ;
1003
+ union_data_range_uncached ( cx, variant, base_offset, out) ;
989
1004
}
990
1005
}
991
1006
}
@@ -1185,7 +1200,7 @@ impl<'rt, 'tcx, M: Machine<'tcx>> ValueVisitor<'tcx, M> for ValidityVisitor<'rt,
1185
1200
// This is the size in bytes of the whole array. (This checks for overflow.)
1186
1201
let size = layout. size * len;
1187
1202
// If the size is 0, there is nothing to check.
1188
- // (`size` can only be 0 of `len` is 0, and empty arrays are always valid.)
1203
+ // (`size` can only be 0 if `len` is 0, and empty arrays are always valid.)
1189
1204
if size == Size :: ZERO {
1190
1205
return Ok ( ( ) ) ;
1191
1206
}
0 commit comments