Replace offset_after_field with offsets
This commit is contained in:
parent
791fb778cc
commit
9482bce56e
5 changed files with 47 additions and 76 deletions
|
|
@ -511,11 +511,11 @@ pub struct Struct {
|
|||
/// If true, the size is exact, otherwise it's only a lower bound.
|
||||
pub sized: bool,
|
||||
|
||||
/// Offsets for the first byte after each field.
|
||||
/// That is, field_offset(i) = offset_after_field[i - 1] and the
|
||||
/// whole structure's size is the last offset, excluding padding.
|
||||
// FIXME(eddyb) use small vector optimization for the common case.
|
||||
pub offset_after_field: Vec<Size>
|
||||
/// Offsets for the first byte of each field.
|
||||
/// FIXME(eddyb) use small vector optimization for the common case.
|
||||
pub offsets: Vec<Size>,
|
||||
|
||||
pub min_size: Size,
|
||||
}
|
||||
|
||||
impl<'a, 'gcx, 'tcx> Struct {
|
||||
|
|
@ -524,7 +524,8 @@ impl<'a, 'gcx, 'tcx> Struct {
|
|||
align: if packed { dl.i8_align } else { dl.aggregate_align },
|
||||
packed: packed,
|
||||
sized: true,
|
||||
offset_after_field: vec![]
|
||||
offsets: vec![],
|
||||
min_size: Size::from_bytes(0),
|
||||
}
|
||||
}
|
||||
|
||||
|
|
@ -534,12 +535,14 @@ impl<'a, 'gcx, 'tcx> Struct {
|
|||
scapegoat: Ty<'gcx>)
|
||||
-> Result<(), LayoutError<'gcx>>
|
||||
where I: Iterator<Item=Result<&'a Layout, LayoutError<'gcx>>> {
|
||||
self.offset_after_field.reserve(fields.size_hint().0);
|
||||
self.offsets.reserve(fields.size_hint().0);
|
||||
|
||||
let mut offset = self.min_size;
|
||||
|
||||
for field in fields {
|
||||
if !self.sized {
|
||||
bug!("Struct::extend: field #{} of `{}` comes after unsized field",
|
||||
self.offset_after_field.len(), scapegoat);
|
||||
self.offsets.len(), scapegoat);
|
||||
}
|
||||
|
||||
let field = field?;
|
||||
|
|
@ -548,34 +551,29 @@ impl<'a, 'gcx, 'tcx> Struct {
|
|||
}
|
||||
|
||||
// Invariant: offset < dl.obj_size_bound() <= 1<<61
|
||||
let mut offset = if !self.packed {
|
||||
if !self.packed {
|
||||
let align = field.align(dl);
|
||||
self.align = self.align.max(align);
|
||||
self.offset_after_field.last_mut().map_or(Size::from_bytes(0), |last| {
|
||||
*last = last.abi_align(align);
|
||||
*last
|
||||
})
|
||||
} else {
|
||||
self.offset_after_field.last().map_or(Size::from_bytes(0), |&last| last)
|
||||
};
|
||||
offset = offset.abi_align(align);
|
||||
}
|
||||
|
||||
self.offsets.push(offset);
|
||||
|
||||
|
||||
offset = offset.checked_add(field.size(dl), dl)
|
||||
.map_or(Err(LayoutError::SizeOverflow(scapegoat)), Ok)?;
|
||||
|
||||
self.offset_after_field.push(offset);
|
||||
}
|
||||
|
||||
self.min_size = offset;
|
||||
|
||||
Ok(())
|
||||
}
|
||||
|
||||
/// Get the size without trailing alignment padding.
|
||||
pub fn min_size(&self) -> Size {
|
||||
self.offset_after_field.last().map_or(Size::from_bytes(0), |&last| last)
|
||||
}
|
||||
|
||||
/// Get the size with trailing aligment padding.
|
||||
pub fn stride(&self) -> Size {
|
||||
self.min_size().abi_align(self.align)
|
||||
self.min_size.abi_align(self.align)
|
||||
}
|
||||
|
||||
/// Determine whether a structure would be zero-sized, given its fields.
|
||||
|
|
@ -671,15 +669,6 @@ impl<'a, 'gcx, 'tcx> Struct {
|
|||
}
|
||||
Ok(None)
|
||||
}
|
||||
|
||||
pub fn offset_of_field(&self, index: usize) -> Size {
|
||||
assert!(index < self.offset_after_field.len());
|
||||
if index == 0 {
|
||||
Size::from_bytes(0)
|
||||
} else {
|
||||
self.offset_after_field[index-1]
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/// An untagged union.
|
||||
|
|
@ -1138,7 +1127,7 @@ impl<'a, 'gcx, 'tcx> Layout {
|
|||
});
|
||||
let mut st = Struct::new(dl, false);
|
||||
st.extend(dl, discr.iter().map(Ok).chain(fields), ty)?;
|
||||
size = cmp::max(size, st.min_size());
|
||||
size = cmp::max(size, st.min_size);
|
||||
align = align.max(st.align);
|
||||
Ok(st)
|
||||
}).collect::<Result<Vec<_>, _>>()?;
|
||||
|
|
@ -1171,12 +1160,16 @@ impl<'a, 'gcx, 'tcx> Layout {
|
|||
let old_ity_size = Int(min_ity).size(dl);
|
||||
let new_ity_size = Int(ity).size(dl);
|
||||
for variant in &mut variants {
|
||||
for offset in &mut variant.offset_after_field {
|
||||
for offset in &mut variant.offsets[1..] {
|
||||
if *offset > old_ity_size {
|
||||
break;
|
||||
}
|
||||
*offset = new_ity_size;
|
||||
}
|
||||
// We might be making the struct larger.
|
||||
if variant.min_size <= old_ity_size {
|
||||
variant.min_size = new_ity_size;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
|||
|
|
@ -738,7 +738,7 @@ impl LateLintPass for VariantSizeDifferences {
|
|||
.zip(variants)
|
||||
.map(|(variant, variant_layout)| {
|
||||
// Subtract the size of the enum discriminant
|
||||
let bytes = variant_layout.min_size().bytes()
|
||||
let bytes = variant_layout.min_size.bytes()
|
||||
.saturating_sub(discr_size);
|
||||
|
||||
debug!("- variant `{}` is {} bytes large", variant.node.name, bytes);
|
||||
|
|
|
|||
|
|
@ -632,7 +632,7 @@ fn struct_field_ptr<'blk, 'tcx>(bcx: &BlockAndBuilder<'blk, 'tcx>,
|
|||
let meta = val.meta;
|
||||
|
||||
|
||||
let offset = st.offset_of_field(ix).bytes();
|
||||
let offset = st.offsets[ix].bytes();
|
||||
let unaligned_offset = C_uint(bcx.ccx(), offset);
|
||||
|
||||
// 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
|
|||
let lldiscr = C_integral(Type::from_integer(ccx, d), discr.0 as u64, true);
|
||||
let mut vals_with_discr = vec![lldiscr];
|
||||
vals_with_discr.extend_from_slice(vals);
|
||||
let mut contents = build_const_struct(ccx, &variant.offset_after_field[..],
|
||||
&vals_with_discr[..], variant.packed);
|
||||
let needed_padding = l.size(dl).bytes() - variant.min_size().bytes();
|
||||
let mut contents = build_const_struct(ccx, &variant,
|
||||
&vals_with_discr[..]);
|
||||
let needed_padding = l.size(dl).bytes() - variant.min_size.bytes();
|
||||
if needed_padding > 0 {
|
||||
contents.push(padding(ccx, needed_padding));
|
||||
}
|
||||
|
|
@ -711,7 +711,7 @@ pub fn trans_const<'a, 'tcx>(ccx: &CrateContext<'a, 'tcx>, t: Ty<'tcx>, discr: D
|
|||
layout::Univariant { ref variant, .. } => {
|
||||
assert_eq!(discr, Disr(0));
|
||||
let contents = build_const_struct(ccx,
|
||||
&variant.offset_after_field[..], vals, variant.packed);
|
||||
&variant, vals);
|
||||
C_struct(ccx, &contents[..], variant.packed)
|
||||
}
|
||||
layout::Vector { .. } => {
|
||||
|
|
@ -728,9 +728,7 @@ pub fn trans_const<'a, 'tcx>(ccx: &CrateContext<'a, 'tcx>, t: Ty<'tcx>, discr: D
|
|||
}
|
||||
layout::StructWrappedNullablePointer { ref nonnull, nndiscr, .. } => {
|
||||
if discr.0 == nndiscr {
|
||||
C_struct(ccx, &build_const_struct(ccx,
|
||||
&nonnull.offset_after_field[..],
|
||||
vals, nonnull.packed),
|
||||
C_struct(ccx, &build_const_struct(ccx, &nonnull, vals),
|
||||
false)
|
||||
} else {
|
||||
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
|
|||
// field; see #8506.
|
||||
C_null(type_of::sizing_type_of(ccx, ty))
|
||||
}).collect::<Vec<ValueRef>>();
|
||||
C_struct(ccx, &build_const_struct(ccx,
|
||||
&nonnull.offset_after_field[..],
|
||||
&vals[..],
|
||||
false),
|
||||
C_struct(ccx, &build_const_struct(ccx, &nonnull, &vals[..]),
|
||||
false)
|
||||
}
|
||||
}
|
||||
|
|
@ -759,11 +754,10 @@ pub fn trans_const<'a, 'tcx>(ccx: &CrateContext<'a, 'tcx>, t: Ty<'tcx>, discr: D
|
|||
/// a two-element struct will locate it at offset 4, and accesses to it
|
||||
/// will read the wrong memory.
|
||||
fn build_const_struct<'a, 'tcx>(ccx: &CrateContext<'a, 'tcx>,
|
||||
offset_after_field: &[layout::Size],
|
||||
vals: &[ValueRef],
|
||||
packed: bool)
|
||||
st: &layout::Struct,
|
||||
vals: &[ValueRef])
|
||||
-> Vec<ValueRef> {
|
||||
assert_eq!(vals.len(), offset_after_field.len());
|
||||
assert_eq!(vals.len(), st.offsets.len());
|
||||
|
||||
if vals.len() == 0 {
|
||||
return Vec::new();
|
||||
|
|
@ -772,24 +766,19 @@ fn build_const_struct<'a, 'tcx>(ccx: &CrateContext<'a, 'tcx>,
|
|||
// offset of current value
|
||||
let mut offset = 0;
|
||||
let mut cfields = Vec::new();
|
||||
let target_offsets = offset_after_field.iter().map(|i| i.bytes());
|
||||
for (&val, target_offset) in vals.iter().zip(target_offsets) {
|
||||
assert!(!is_undef(val));
|
||||
cfields.push(val);
|
||||
offset += machine::llsize_of_alloc(ccx, val_ty(val));
|
||||
if !packed {
|
||||
let val_align = machine::llalign_of_min(ccx, val_ty(val));
|
||||
offset = roundup(offset, val_align);
|
||||
}
|
||||
if offset != target_offset {
|
||||
let offsets = st.offsets.iter().map(|i| i.bytes());
|
||||
for (&val, target_offset) in vals.iter().zip(offsets) {
|
||||
if offset < target_offset {
|
||||
cfields.push(padding(ccx, target_offset - offset));
|
||||
offset = target_offset;
|
||||
}
|
||||
assert!(!is_undef(val));
|
||||
cfields.push(val);
|
||||
offset += machine::llsize_of_alloc(ccx, val_ty(val));
|
||||
}
|
||||
|
||||
let size = offset_after_field.last().unwrap();
|
||||
if offset < size.bytes() {
|
||||
cfields.push(padding(ccx, size.bytes() - offset));
|
||||
if offset < st.min_size.bytes() {
|
||||
cfields.push(padding(ccx, st.min_size.bytes() - offset));
|
||||
}
|
||||
|
||||
cfields
|
||||
|
|
|
|||
|
|
@ -127,7 +127,7 @@ pub fn type_is_imm_pair<'a, 'tcx>(ccx: &CrateContext<'a, 'tcx>, ty: Ty<'tcx>)
|
|||
Layout::FatPointer { .. } => true,
|
||||
Layout::Univariant { ref variant, .. } => {
|
||||
// There must be only 2 fields.
|
||||
if variant.offset_after_field.len() != 2 {
|
||||
if variant.offsets.len() != 2 {
|
||||
return false;
|
||||
}
|
||||
|
||||
|
|
|
|||
|
|
@ -335,20 +335,9 @@ pub fn size_and_align_of_dst<'blk, 'tcx>(bcx: &BlockAndBuilder<'blk, 'tcx>,
|
|||
let layout = ccx.layout_of(t);
|
||||
debug!("DST {} layout: {:?}", t, layout);
|
||||
|
||||
// Returns size in bytes of all fields except the last one
|
||||
// (we will be recursing on the last one).
|
||||
fn local_prefix_bytes(variant: &ty::layout::Struct) -> u64 {
|
||||
let fields = variant.offset_after_field.len();
|
||||
if fields > 1 {
|
||||
variant.offset_after_field[fields - 2].bytes()
|
||||
} else {
|
||||
0
|
||||
}
|
||||
}
|
||||
|
||||
let (sized_size, sized_align) = match *layout {
|
||||
ty::layout::Layout::Univariant { ref variant, .. } => {
|
||||
(local_prefix_bytes(variant), variant.align.abi())
|
||||
(variant.offsets.last().map_or(0, |o| o.bytes()), variant.align.abi())
|
||||
}
|
||||
_ => {
|
||||
bug!("size_and_align_of_dst: expcted Univariant for `{}`, found {:#?}",
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue