Skip to content

Commit 1cdc0fb

Browse files
authored
Auto merge of #36904 - camlorn:field_offsets_refactor, r=eddyb
Refactor layout to store offsets of fields, not offsets after fields This is the next PR moving us towards being able to reorder struct fields. The old code implicitly stored the offset of the first field. This is inadequate because the first field may no longer be offset 0 in future. This PR refactors `layout` to use a `offsets` vector instead of a `offset_after_field` vector.
2 parents 8991ffc + 9482bce commit 1cdc0fb

File tree

5 files changed

+47
-76
lines changed

5 files changed

+47
-76
lines changed

Diff for: src/librustc/ty/layout.rs

+26-33
Original file line numberDiff line numberDiff line change
@@ -511,11 +511,11 @@ pub struct Struct {
511511
/// If true, the size is exact, otherwise it's only a lower bound.
512512
pub sized: bool,
513513

514-
/// Offsets for the first byte after each field.
515-
/// That is, field_offset(i) = offset_after_field[i - 1] and the
516-
/// whole structure's size is the last offset, excluding padding.
517-
// FIXME(eddyb) use small vector optimization for the common case.
518-
pub offset_after_field: Vec<Size>
514+
/// Offsets for the first byte of each field.
515+
/// FIXME(eddyb) use small vector optimization for the common case.
516+
pub offsets: Vec<Size>,
517+
518+
pub min_size: Size,
519519
}
520520

521521
impl<'a, 'gcx, 'tcx> Struct {
@@ -524,7 +524,8 @@ impl<'a, 'gcx, 'tcx> Struct {
524524
align: if packed { dl.i8_align } else { dl.aggregate_align },
525525
packed: packed,
526526
sized: true,
527-
offset_after_field: vec![]
527+
offsets: vec![],
528+
min_size: Size::from_bytes(0),
528529
}
529530
}
530531

@@ -534,12 +535,14 @@ impl<'a, 'gcx, 'tcx> Struct {
534535
scapegoat: Ty<'gcx>)
535536
-> Result<(), LayoutError<'gcx>>
536537
where I: Iterator<Item=Result<&'a Layout, LayoutError<'gcx>>> {
537-
self.offset_after_field.reserve(fields.size_hint().0);
538+
self.offsets.reserve(fields.size_hint().0);
539+
540+
let mut offset = self.min_size;
538541

539542
for field in fields {
540543
if !self.sized {
541544
bug!("Struct::extend: field #{} of `{}` comes after unsized field",
542-
self.offset_after_field.len(), scapegoat);
545+
self.offsets.len(), scapegoat);
543546
}
544547

545548
let field = field?;
@@ -548,34 +551,29 @@ impl<'a, 'gcx, 'tcx> Struct {
548551
}
549552

550553
// Invariant: offset < dl.obj_size_bound() <= 1<<61
551-
let mut offset = if !self.packed {
554+
if !self.packed {
552555
let align = field.align(dl);
553556
self.align = self.align.max(align);
554-
self.offset_after_field.last_mut().map_or(Size::from_bytes(0), |last| {
555-
*last = last.abi_align(align);
556-
*last
557-
})
558-
} else {
559-
self.offset_after_field.last().map_or(Size::from_bytes(0), |&last| last)
560-
};
557+
offset = offset.abi_align(align);
558+
}
559+
560+
self.offsets.push(offset);
561+
561562

562563
offset = offset.checked_add(field.size(dl), dl)
563564
.map_or(Err(LayoutError::SizeOverflow(scapegoat)), Ok)?;
564-
565-
self.offset_after_field.push(offset);
566565
}
567566

567+
self.min_size = offset;
568+
568569
Ok(())
569570
}
570571

571572
/// Get the size without trailing alignment padding.
572-
pub fn min_size(&self) -> Size {
573-
self.offset_after_field.last().map_or(Size::from_bytes(0), |&last| last)
574-
}
575573
576574
/// Get the size with trailing aligment padding.
577575
pub fn stride(&self) -> Size {
578-
self.min_size().abi_align(self.align)
576+
self.min_size.abi_align(self.align)
579577
}
580578

581579
/// Determine whether a structure would be zero-sized, given its fields.
@@ -671,15 +669,6 @@ impl<'a, 'gcx, 'tcx> Struct {
671669
}
672670
Ok(None)
673671
}
674-
675-
pub fn offset_of_field(&self, index: usize) -> Size {
676-
assert!(index < self.offset_after_field.len());
677-
if index == 0 {
678-
Size::from_bytes(0)
679-
} else {
680-
self.offset_after_field[index-1]
681-
}
682-
}
683672
}
684673

685674
/// An untagged union.
@@ -1138,7 +1127,7 @@ impl<'a, 'gcx, 'tcx> Layout {
11381127
});
11391128
let mut st = Struct::new(dl, false);
11401129
st.extend(dl, discr.iter().map(Ok).chain(fields), ty)?;
1141-
size = cmp::max(size, st.min_size());
1130+
size = cmp::max(size, st.min_size);
11421131
align = align.max(st.align);
11431132
Ok(st)
11441133
}).collect::<Result<Vec<_>, _>>()?;
@@ -1171,12 +1160,16 @@ impl<'a, 'gcx, 'tcx> Layout {
11711160
let old_ity_size = Int(min_ity).size(dl);
11721161
let new_ity_size = Int(ity).size(dl);
11731162
for variant in &mut variants {
1174-
for offset in &mut variant.offset_after_field {
1163+
for offset in &mut variant.offsets[1..] {
11751164
if *offset > old_ity_size {
11761165
break;
11771166
}
11781167
*offset = new_ity_size;
11791168
}
1169+
// We might be making the struct larger.
1170+
if variant.min_size <= old_ity_size {
1171+
variant.min_size = new_ity_size;
1172+
}
11801173
}
11811174
}
11821175

Diff for: src/librustc_lint/types.rs

+1-1
Original file line numberDiff line numberDiff line change
@@ -738,7 +738,7 @@ impl LateLintPass for VariantSizeDifferences {
738738
.zip(variants)
739739
.map(|(variant, variant_layout)| {
740740
// Subtract the size of the enum discriminant
741-
let bytes = variant_layout.min_size().bytes()
741+
let bytes = variant_layout.min_size.bytes()
742742
.saturating_sub(discr_size);
743743

744744
debug!("- variant `{}` is {} bytes large", variant.node.name, bytes);

Diff for: src/librustc_trans/adt.rs

+18-29
Original file line numberDiff line numberDiff line change
@@ -632,7 +632,7 @@ fn struct_field_ptr<'blk, 'tcx>(bcx: &BlockAndBuilder<'blk, 'tcx>,
632632
let meta = val.meta;
633633

634634

635-
let offset = st.offset_of_field(ix).bytes();
635+
let offset = st.offsets[ix].bytes();
636636
let unaligned_offset = C_uint(bcx.ccx(), offset);
637637

638638
// Get the alignment of the field
@@ -695,9 +695,9 @@ pub fn trans_const<'a, 'tcx>(ccx: &CrateContext<'a, 'tcx>, t: Ty<'tcx>, discr: D
695695
let lldiscr = C_integral(Type::from_integer(ccx, d), discr.0 as u64, true);
696696
let mut vals_with_discr = vec![lldiscr];
697697
vals_with_discr.extend_from_slice(vals);
698-
let mut contents = build_const_struct(ccx, &variant.offset_after_field[..],
699-
&vals_with_discr[..], variant.packed);
700-
let needed_padding = l.size(dl).bytes() - variant.min_size().bytes();
698+
let mut contents = build_const_struct(ccx, &variant,
699+
&vals_with_discr[..]);
700+
let needed_padding = l.size(dl).bytes() - variant.min_size.bytes();
701701
if needed_padding > 0 {
702702
contents.push(padding(ccx, needed_padding));
703703
}
@@ -711,7 +711,7 @@ pub fn trans_const<'a, 'tcx>(ccx: &CrateContext<'a, 'tcx>, t: Ty<'tcx>, discr: D
711711
layout::Univariant { ref variant, .. } => {
712712
assert_eq!(discr, Disr(0));
713713
let contents = build_const_struct(ccx,
714-
&variant.offset_after_field[..], vals, variant.packed);
714+
&variant, vals);
715715
C_struct(ccx, &contents[..], variant.packed)
716716
}
717717
layout::Vector { .. } => {
@@ -728,9 +728,7 @@ pub fn trans_const<'a, 'tcx>(ccx: &CrateContext<'a, 'tcx>, t: Ty<'tcx>, discr: D
728728
}
729729
layout::StructWrappedNullablePointer { ref nonnull, nndiscr, .. } => {
730730
if discr.0 == nndiscr {
731-
C_struct(ccx, &build_const_struct(ccx,
732-
&nonnull.offset_after_field[..],
733-
vals, nonnull.packed),
731+
C_struct(ccx, &build_const_struct(ccx, &nonnull, vals),
734732
false)
735733
} else {
736734
let fields = compute_fields(ccx, t, nndiscr as usize, false);
@@ -739,10 +737,7 @@ pub fn trans_const<'a, 'tcx>(ccx: &CrateContext<'a, 'tcx>, t: Ty<'tcx>, discr: D
739737
// field; see #8506.
740738
C_null(type_of::sizing_type_of(ccx, ty))
741739
}).collect::<Vec<ValueRef>>();
742-
C_struct(ccx, &build_const_struct(ccx,
743-
&nonnull.offset_after_field[..],
744-
&vals[..],
745-
false),
740+
C_struct(ccx, &build_const_struct(ccx, &nonnull, &vals[..]),
746741
false)
747742
}
748743
}
@@ -759,11 +754,10 @@ pub fn trans_const<'a, 'tcx>(ccx: &CrateContext<'a, 'tcx>, t: Ty<'tcx>, discr: D
759754
/// a two-element struct will locate it at offset 4, and accesses to it
760755
/// will read the wrong memory.
761756
fn build_const_struct<'a, 'tcx>(ccx: &CrateContext<'a, 'tcx>,
762-
offset_after_field: &[layout::Size],
763-
vals: &[ValueRef],
764-
packed: bool)
757+
st: &layout::Struct,
758+
vals: &[ValueRef])
765759
-> Vec<ValueRef> {
766-
assert_eq!(vals.len(), offset_after_field.len());
760+
assert_eq!(vals.len(), st.offsets.len());
767761

768762
if vals.len() == 0 {
769763
return Vec::new();
@@ -772,24 +766,19 @@ fn build_const_struct<'a, 'tcx>(ccx: &CrateContext<'a, 'tcx>,
772766
// offset of current value
773767
let mut offset = 0;
774768
let mut cfields = Vec::new();
775-
let target_offsets = offset_after_field.iter().map(|i| i.bytes());
776-
for (&val, target_offset) in vals.iter().zip(target_offsets) {
777-
assert!(!is_undef(val));
778-
cfields.push(val);
779-
offset += machine::llsize_of_alloc(ccx, val_ty(val));
780-
if !packed {
781-
let val_align = machine::llalign_of_min(ccx, val_ty(val));
782-
offset = roundup(offset, val_align);
783-
}
784-
if offset != target_offset {
769+
let offsets = st.offsets.iter().map(|i| i.bytes());
770+
for (&val, target_offset) in vals.iter().zip(offsets) {
771+
if offset < target_offset {
785772
cfields.push(padding(ccx, target_offset - offset));
786773
offset = target_offset;
787774
}
775+
assert!(!is_undef(val));
776+
cfields.push(val);
777+
offset += machine::llsize_of_alloc(ccx, val_ty(val));
788778
}
789779

790-
let size = offset_after_field.last().unwrap();
791-
if offset < size.bytes() {
792-
cfields.push(padding(ccx, size.bytes() - offset));
780+
if offset < st.min_size.bytes() {
781+
cfields.push(padding(ccx, st.min_size.bytes() - offset));
793782
}
794783

795784
cfields

Diff for: src/librustc_trans/common.rs

+1-1
Original file line numberDiff line numberDiff line change
@@ -127,7 +127,7 @@ pub fn type_is_imm_pair<'a, 'tcx>(ccx: &CrateContext<'a, 'tcx>, ty: Ty<'tcx>)
127127
Layout::FatPointer { .. } => true,
128128
Layout::Univariant { ref variant, .. } => {
129129
// There must be only 2 fields.
130-
if variant.offset_after_field.len() != 2 {
130+
if variant.offsets.len() != 2 {
131131
return false;
132132
}
133133

Diff for: src/librustc_trans/glue.rs

+1-12
Original file line numberDiff line numberDiff line change
@@ -335,20 +335,9 @@ pub fn size_and_align_of_dst<'blk, 'tcx>(bcx: &BlockAndBuilder<'blk, 'tcx>,
335335
let layout = ccx.layout_of(t);
336336
debug!("DST {} layout: {:?}", t, layout);
337337

338-
// Returns size in bytes of all fields except the last one
339-
// (we will be recursing on the last one).
340-
fn local_prefix_bytes(variant: &ty::layout::Struct) -> u64 {
341-
let fields = variant.offset_after_field.len();
342-
if fields > 1 {
343-
variant.offset_after_field[fields - 2].bytes()
344-
} else {
345-
0
346-
}
347-
}
348-
349338
let (sized_size, sized_align) = match *layout {
350339
ty::layout::Layout::Univariant { ref variant, .. } => {
351-
(local_prefix_bytes(variant), variant.align.abi())
340+
(variant.offsets.last().map_or(0, |o| o.bytes()), variant.align.abi())
352341
}
353342
_ => {
354343
bug!("size_and_align_of_dst: expcted Univariant for `{}`, found {:#?}",

0 commit comments

Comments
 (0)